Change Display Format Of List<KeyValuePair<string, string>> - c#

I am using a Xamarin.Forms Picker and it's being populated by a List<KeyValuePair<string, string>>. The issue is that it isn't displaying the way I would like.
XAML:
<Picker x:Name="VersionPicker" ItemsSource="{Binding}"/>
C#:
Dictionary<string, string> VersionDictionary = new Dictionary<string, string>()
{
{ "asv1901", "American Standard Version" },
{ "bbe", "Bible In Basic English" },
};
List<KeyValuePair<string, string>> VersionList = VersionDictionary.ToList();
VersionPicker.BindingContext = VersionList;
What it produces is like this...
[asv1901, American Standard Version]
I would like Picker to have something along these lines...
American Standard Version (asv1901)
Is there a way to do this? XAML or C# would be fine (since it's purely a visual change, I was thinking XAML or a converter might make the most sense).

A shout-out to jdweng (since he/she just did a comment and not an answer)...
Dictionary<string, string> VersionDictionary = new Dictionary<string, string>()
{
{ "asv1901", "American Standard Version" },
{ "bbe", "Bible In Basic English" },
};
// take the dictionary<string, string>, turn it into an ienumerable<keyvaluepair<string, string>>, use linq to output the contents, format a new string based on those contents, turn it into list<string>
// "Bible In Basic English (bbe)"
var VersionList = VersionDictionary.AsEnumerable().Select(x => string.Format("{0} ({1})", x.Value, x.Key)).ToList();
VersionPicker.BindingContext = VersionList;
To get that choice back to the appropriate format...
private void VersionPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var selecteditem = VersionPicker.SelectedItem.ToString();
// single quotes make it type Char while double quotes make it type String
Char delimiter = '(';
// create an array from the string separated by the delimiter
String[] selecteditemparts = selecteditem.Split(delimiter);
// take off the end space
var selecteditemvalue = selecteditemparts[0].Substring(0, (selecteditemparts[0].Length - 1));
// take off the end )
var selecteditemkey = selecteditemparts[1].Substring(0, (selecteditemparts[1].Length - 1));
}
As a secondary option (and the one I ended up using)...
Dictionary<string, string> VersionDictionary = new Dictionary<string, string>()
{
{ "asv1901", "American Standard Version" },
{ "bbe", "Bible In Basic English" },
};
var VersionList = new List<string>();
// keyvaluepair is a single instance and dictionary is a collection of keyvaluepairs
foreach (KeyValuePair<string, string> version in VersionDictionary)
{
var key = version.Key.ToUpper();
var value = version.Value;
// "Bible In Basic English (BBE)"
VersionList.Add(string.Format("{0} ({1})", value, key));
}
It just makes more sense to my rather novice coding brain. I'm sure jdweng's linq example is much more concise.

Related

How to loop through multiple dictionaries to obtain KVP?

I currently have 20 Dictionary<string, Vector3> that are storing TimeStamp Key and Vector3 Value.
E.g.
Dictionary<string, Vector3> rWrist = new Dictionary<string, Vector3>();
Dictionary<string, Vector3> rThumbProximal = new Dictionary<string, Vector3>();
Dictionary<string, Vector3> rThumbDistal = new Dictionary<string, Vector3>();
Dictionary<string, Vector3> rThumbTip = new Dictionary<string, Vector3>();
Dictionary<string, Vector3> rIndexKnuckle = new Dictionary<string, Vector3>();
On exit, I am attempting to loop through each dictionary to generate a CSV with TimeStamp and X,Y,Z coordinates.
I was successful in generating a one to two CSVs manually.
E.g.
foreach (KeyValuePair<string, Vector3> kvp in rWrist)
{
writer.WriteLine("{0},{1},{2},{3}", kvp.Key, kvp.Value.x, kvp.Value.y, kvp.Value.z);
}
But... to do this manually for all 20 dictionaries would be a pain. I am pretty lost on how I could iterate through each dictionary at once.
E.g.
for (int i = 0; i < paths.Count; i++)
{
if (!File.Exists(paths[i]))
{
File.WriteAllText(paths[i], null);
}
using (var writer = new StreamWriter(paths[i]))
{
writer.WriteLine("{0},{1},{2},{3}", "Time", "xPos", "yPos", "zPos");
foreach (KeyValuePair<string, Vector3> kvp in LOOP-THROUGH-MULTIPLE-DICTIONARIES-HERE)
{
writer.WriteLine("{0},{1},{2},{3}", kvp.Key, kvp.Value.x, kvp.Value.y, kvp.Value.z);
}
}
}
I'm not a software developer by trade so any help would be greatly appreciated!
Edit for Clarity:
I am using HoloLens2 to poll positional data every tick
Using the internal clock - each tick is stored as a Key and the value is assigned the Vector3 position of that joint at that tick
Each dictionary may or may not have the same TimeStamps if HoloLens2 doesn't detect a finger pose that tick.
I need to export different .CSV for each joint for Data Analysis
I need to export different .CSV for each joint for Data Analysis
From my understanding, that requirement contradicts your previous statement:
I am pretty lost on how I could iterate through each dictionary at once.
, but if you need to export the joint data to separate .CSV files, I would suggest something similar to the following:
var vectorDataByJointName = new Dictionary<string, Dictionary<string, Vector3>>
{
[nameof(rWrist)] = rWrist,
[nameof(rThumbProximal)] = rThumbProximal,
[nameof(rThumbDistal)] = rThumbDistal,
[nameof(rThumbTip)] = rThumbTip,
[nameof(rIndexKnuckle)] = rIndexKnuckle,
// and so on for the remaining joints
};
foreach (var jointVectorData in vectorDataByJointName)
{
// File creation here (using jointVectorData.Key as file name?)
writer.WriteLine("{0},{1},{2},{3}", "Time", "xPos", "yPos", "zPos");
foreach (var kvp in jointVectorData.Value)
{
writer.WriteLine("{0},{1},{2},{3}", kvp.Key, kvp.Value.x, kvp.Value.y, kvp.Value.z);
}
}
(nameof(rWrist) will simply produce the string "rWrist", and may be replaced by strings directly if that's preferred (e.g. ["Right wrist"] = rWrist rather than [nameof(rWrist)] = rWrist).)
Is it possible instead of thinking about looping through all dictionaries at the same time you actually need to keep a master list of all your keys, and loop through all possible dictionary keys? Which in your instance are timestamps? This will then allow you to operate on each dictionary at the same time. Here is an example I did in LinqPad. The Dump() is similar to WriteLine().
var timestampKeys = new [] {"timestamp1","timestamp2","timestamp3"};
Dictionary<string, string> rWrist = new Dictionary<string, string>();
Dictionary<string, string> rThumbProximal = new Dictionary<string, string>();
rWrist.Add("timestamp1","vectorWrist1");
rWrist.Add("timestamp3","vectorWrist2");
rThumbProximal.Add("timestamp1","vectorThumb1");
rThumbProximal.Add("timestamp2","vectorThumb2");
rThumbProximal.Add("timestamp3","vectorThumb3");
foreach(var timestampKey in timestampKeys)
{
if(rWrist.ContainsKey(timestampKey))
rWrist[timestampKey].Dump();
if(rThumbProximal.ContainsKey(timestampKey))
rThumbProximal[timestampKey].Dump();
}
// outputs:
//vectorWrist1
//vectorThumb1
//vectorThumb2
//vectorWrist2
//vectorThumb3
You could create an IEnumerable<Dictionary<string, Vector3>> (many ways to go about doing that) then use SelectMany to flatten the key-value pairs into a single dimension:
var dictionaries = new[]
{
rWrist,
rThumbProximal,
...
}
foreach( var kvp in dictionaries.SelectMany(d => d) )
{
...
}
Alternatively, just chain Enumberable.Concat calls together
var kvPairs = rWrist.Concat( rThumbProximal )
.Concat( rThumbDistal )
... etc ...;
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// key = body part
// value = that body part's dictionary
Dictionary<string, Dictionary<string, string>> bigDic = new Dictionary<string, Dictionary<string, string>>();
// <string, string> instead of <string, Vector3>, for demonstration. You can use Vector3 as value without worries.
bigDic.Add("smallDic", new Dictionary<string, string>());
bigDic["smallDic"].Add("12345", "Old Position");
// write
foreach (Dictionary<string, string> sd in bigDic.Values)
{
sd.Add("12346", "New Position");
}
// read
foreach (Dictionary<string, string> sd in bigDic.Values)
{
foreach (string timestamp in sd.Keys)
{
Console.WriteLine(timestamp + ": " + sd[timestamp]);
}
}
}
}
This way, you can access the dictionary through string as keys (Maybe each body part's name, in this case), or simply iterate through them to do same process on each one.
With the case you're mentioning, my guess is you probably won't change the values when iterating through the dictionaries. However if you need to do so, change a dictionary's value while iterating through it is not viable. You can check here for workarounds.

How can I insert values into a multi-layer Dictionary in C#?

I have to write a Dictionary which will be
Dictionary<int, Dictionary<string, string>> dictionary = new Dictionary<int, Dictionary<string, string>>() { };
so later i'll just check and get values like
if (dictionary[index].key* == value) { stuff; } //*or maybe it's [index][key], that's not the matter
I just don't know and understand how to write the various elements inside the dictionary (i already searched here and online), the proper syntax, anything i try gets an error. Hope you can help, thank you in advance!
The name index isn't really appropriate, because dictionaries don't use indices they use keys.
However, to add a new sub-dictionary:
dictionary[i] = new Dictionary<string, string>();
To add / replace a value in an existing sub-dictionary:
dictionary[i][key] = value;
If you want to safely insert a new value when a sub-dictionary may or may not have been created, you could create an extension method:
public static void Insert(this Dictionary<int, Dictionary<string, string>> dict, int i, string key, string value)
{
if (!dict.ContainsKey(i)) dict[i] = new Dictionary<string, string>();
dict[i][key] = value;
}
Then use like this:
dictionary.Insert(1, "SomeKey", "SomeValue");
Just note that this will overwrite keys in the sub-dictionary if the same key is inserted more than once.
To insert into this object:
Dictionary<int, Dictionary<string, string>> dictionary = new Dictionary<int, Dictionary<string, string>>() { };
You'll need to do multiple inserts. So something like:
//create the first level and instanciate a new dictionary object
dictionary.Add(1234, new Dictionary<string, string>());
//insert into the dictionary created above
dictionary[1234].Add("test", "test");
dictionary[1234] here returns a Dictionary<string, string> where 1234 is the key added in dictionary.Add(1234, new Dictionary<string, string>());
How about using collection initialisers? This is great if you have constant values that you want the dictionary to contain:
var dictionary = new Dictionary<int, Dictionary<string, string>>() {
[111] = new Dictionary<string, string> {
["nested key1"] = "value 1",
["nested key2"] = "value 2",
["nested key3"] = "value 3",
["nested key4"] = "value 4",
},
[222] = new Dictionary<string, string> {
["nested key5"] = "value 5",
["nested key6"] = "value 6",
["nested key7"] = "value 7",
["nested key8"] = "value 8",
},
};
dictionary has type Dictionary<int, Dictionary<string, string>>, so var b = dictionary[3] has type Dictionary<string, string>, and to get an entry of b use syntax b["Hello"] to get a string.
If you want to write them in one clause, use (dictionary[3])["Hello"]. Since operator[] is left-associative, (dictionary[3])["Hello"] can be written as dictionary[3]["Hello"].

Need help manually adding to a dictionary

I am confused I am trying to manually add entries to a Dictionary but its throwing an error at the first comma. Any help is appreciated thank you.
private Dictionary<string, Dictionary<string, string>> packData =
new Dictionary<string, Dictionary<string, string>>()
{
{
"Test", //issue here
{
"Test" , "Test"
}
};
};
You'll want to be explicit about the inner dictionary:
new Dictionary<string, Dictionary<string, string>>()
{
{
"Test",
new Dictionary<string, string>
{
"Test" , "Test"
}
};
};
The rule to follow here is "imagine if the thing in the braces was replaced with a call to Add". In your original code, we would have lowered this to:
temp = new Dictionary<string, Dictionary<string, string>>();
temp.Add("Test", { "Test", "Test" });
Which is not legal code. But
temp = new Dictionary<string, Dictionary<string, string>>();
temp.Add("Test", new Dictionary<string, string>(){ "Test", "Test" });
is legal, and in turn corresponds to
temp = new Dictionary<string, Dictionary<string, string>>();
temp2 = new Dictionary<string, string>();
temp2.Add("Test", "Test");
temp.Add("Test", temp2);
I often find when I'm confused that it helps to "lower" the code into its more basic form to understand what's going on.
There are some situations in which the compiler is smarter about understanding the intended meaning of nested braces like in your original code, but unfortunately this is not one of them. See the specification for more details about what is and is not supported; you'll want to search for "object initializers" and "collection initializers".

C# sort a dictionary by value

I am sorting a dictionary, consisting of values & keys , by value. I have a hash of words and number of time used, that I want to order by number of time used.
There is a SortedList which is good for a single value , that I want to map it back to the word.
SortedDictionary orders by key, not value.
I could use a custom class, is there a better way.
I did some google searches but I can't find exactly what I am lookign for.
I found the answer
List<KeyValuePair<string, string>> BillsList = aDictionary.ToList();
BillsList.Sort(delegate(KeyValuePair<string, string> firstPair,
KeyValuePair<string, string> nextPair)
{
return firstPair.Value.CompareTo(nextPair.Value);
}
);
This should do it:
Dictionary<string, string> d = new Dictionary<string, string>
{
{"A","Z"},
{"B","Y"},
{"C","X"}
};
d.OrderBy(x=>x.Value).Select(x=>x.Key);
Will return C, B, A.
Here is using Linq and mapping the Count to the Word:
IDictionary<string, int> wordsAndCount = new Dictionary<string, int>
{
{"Batman", 987987987},
{"MeaningOfLife",42},
{"Fun",69},
{"Relaxing",420},
{"This", 2}
};
var result = wordsAndCount.OrderBy(d => d.Value).Select(d => new
{
Word = d.Key,
Count = d.Value
});
Result:

Is this an efficient code for Multi Key Dictionary in a Method Body?

I just want to ask if:
The code below is efficient?
Is there a better way to handle this?
How to code if additional values for tablename/fieldname pair are needed?
We need to use a multi-key dictionary that contains something like (TableName, FieldName, FieldValue).
I searched some answer but the ones I found so far are not applicable to our setup. We are using 3.5 so no Tuple available yet. We are also integrating this script logic with an application that only allows coding "inside" a method body, so we are limited and cannot create a separate class/structure, etc. Our set up is C#/VS 2010.
Any help is appreciated. Thanks in advance!
Dictionary<string, Dictionary<string, string>> tableList = new Dictionary<string, Dictionary<string, string>>();
Dictionary<string, string> fieldList = new Dictionary<string, string>();
// add fields to field list, then add the field lists to the corresponding table list
// clear field list for next table
// values are just hardcoded here to simplify, but is being read from actual objects in the application
fieldList.Add("Field1", "abc");
fieldList.Add("Field2", "def");
fieldList.Add("Field3", "ghi");
fieldList.Add("Field4", "jkl");
tableList.Add("Table1", new Dictionary<string, string>(fieldList));
fieldList.Clear();
fieldList.Add("Field1", "xyz");
fieldList.Add("Field2", "uvw");
fieldList.Add("Field3", "rst");
tableList.Add("Table2", new Dictionary<string, string>(fieldList));
fieldList.Clear();
fieldList.Add("Field1", "123");
fieldList.Add("Field2", "456");
tableList.Add("Table3", new Dictionary<string, string>(fieldList));
fieldList.Clear();
// Display tables and corresponding fields
foreach (KeyValuePair<string, Dictionary<string, string>> fieldList4 in tableList)
{
foreach (KeyValuePair<string, string> fieldList5 in fieldList4.Value)
{
txtMessage.Text = txtMessage.Text + "\r\nTable=" + fieldList4.Key + ", Field=" + fieldList5.Key + " - " + fieldList5.Value;
}
}
// Try to find tables and fields in the lists, and list the value if found
string tableToFind = "Table2";
string fieldToFind = "Field2";
Dictionary<string, string> tableFields = new Dictionary<string, string>();
if (tableList.Keys.Contains(tableToFind) == true)
{
txtMessage.Text = txtMessage.Text = "\r\nTable=" + tableToFind + " exist in table list";
tableList.TryGetValue(tableToFind, out tableFields);
if (tableFields.Keys.Contains(fieldToFind) == true)
{
foreach(KeyValuePair<string, string> fieldData in tableFields)
{
if (fieldData.Key == fieldToFind)
{
txtMessage.Text = txtMessage.Text + "\r\nTable=" + tableToFind + ", Field=" + fieldData.Key +
" with value=" + fieldData.Value + " exist in table list";
break;
}
}
}
}
You can use the compiler to create a composite key for you: Using anonymous types.
var dictionary = new Dictionary<Object, int>();
dictionary.Add(new{Text="A", Number=1}, 1);
dictionary.Add(new{Text="A", Number=2}, 3);
dictionary.Add(new{Text="B", Number=1}, 4);
dictionary.Add(new{Text="B", Number=2}, 5);
var x = dictionary[new{Text="B", Number=2}];
C# will implement Equals and GetHashcode based on your fields. Thus you do get a key which will behave as you would expect.
There's a whole slew of problems and inefficiencies in your code.
If you're going to create multiple dictionaries, create the dictionaries directly. Don't use a separate instance to fill the values and copy from.
Never use string concatenation in a loop like that. Use a StringBuilder or other similar mechanism to build up your strings. You already have your values in a collection so using String.Join() in conjunction with LINQ would clean that up.
Your approach to get values from the dictionary is awkward to say the least. Normally you'd use TryGetValue() alone to attempt to read the key. Your code uses it incorrectly. If you are going to check if the key exists in the dictionary (using Contains()), then there's no point in using TryGetValue(). To make things worse, you did this then searched for the key manually in the inner dictionary by iterating through the key value pairs.
The typical pattern looks like this:
DictValueType value;
if (myDict.TryGetValue(key, out value))
{
// key was in the dictionary, the value is stored in the `value` variable
}
The code you have could be written much much more efficiently like this:
var tableList = new Dictionary<string, Dictionary<string, string>>
{
{ "Table1", new Dictionary<string, string>
{
{ "Field1", "abc" },
{ "Field2", "def" },
{ "Field3", "ghi" },
{ "Field4", "jkl" },
}
},
{ "Table2", new Dictionary<string, string>
{
{ "Field1", "xyz" },
{ "Field2", "uvw" },
{ "Field3", "rst" },
}
},
{ "Table3", new Dictionary<string, string>
{
{ "Field1", "123" },
{ "Field2", "456" },
}
},
};
// Display tables and corresponding fields
txtMessage.Text = String.Join("\r\n",
tableList.SelectMany(table =>
table.Value.Select(fieldList =>
String.Format("Table={0}, Field={1} - {2}",
table.Key, fieldList.Key, fieldList.Value)
)
).ToArray()
);
// (I hope you have this in a separate method)
// Try to find tables and fields in the lists, and list the value if found
string tableToFind = "Table2";
string fieldToFind = "Field2";
var builder = new StringBuilder(txtMessage.Text); // mostly useful if you have a
// lot of different strings to add
Dictionary<string, string> foundTable;
if (tableList.TryGetValue(tableToFind, out foundTable))
{
builder.AppendLine()
.Append("Table=" + tableToFind + " exist in table list");
string foundField;
if (foundTable.TryGetValue(fieldToFind, out foundField))
{
builder.AppendLine()
.AppendFormat("Table={0}, Field={1} with value={2} exist in table list",
tableToFind, fieldToFind, foundField);
}
}
txtMessage.Text = builder.ToString();
Nested dictionaries aren't a bad thing, it's a nice way to organize hierarchies of keys and values. But to keep it maintainable, you generally should encapsulate everything within another class providing methods to manipulate the data without having to manage the dictionaries directly. You can make it both efficient and maintainable. How to implement this is an exercise left to you.
I don't think so many dictionaries would be 'efficient'.
I think the best way would be to add values into the same dictionary multiple times - assuming you want to be able to index them according to one of the indicies (not all):
dictionary.Add("FField1", "xxx");
dictionary.Add("TTable1", "xxx");
Otherwise use a joining character (like '\0') if you want to index them according to all the indicies together.
dictionary.Add("Table1\0Field1", "xxx");

Categories