How to create and populate a nested dictionary with three keys - c#

I have a unique double corresponding to a variation of three strings. I want to populate a dictionary or something such that I can call something like dict[key1][key2][key3] and get the value.
I've tried a whole bunch of things like
Dictionary<string, Dictionary<string, double>> dict = new Dictionary<string, Dictionary<string, double>> {
{ "Foo", {"Bar", 1.2 } },
{ "Foo", {"Test", 3.4 } }
};
Which gives me syntax errors and errors like "Error 4 A namespace cannot directly contain members such as fields or methods"
And
Dictionary<double, Tuple<string, string>> dict = {
{1.23, "Blah", "Foo"}
};
Which gives me errors like "Error 1 Can only use array initializer expressions to assign to array types. Try using a new expression instead."
And
object dict = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
dict["k1"] = new Dictionary<string, Dictionary<string, string>>();
dict["k1"]["k2"] = new Dictionary<string, string>();
dict["k1"]["k2"]["k3"] = 3.5;
Which gives me syntax errors and errors like "Error 2 Invalid token '"k1"' in class, struct, or interface member declaration"
How should I go about this? Thanks in advance.
![enter image description here][1]
Edit: Trying Jonesy's code:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
string[] grades = { "Grade 1", "Grade 5", "Grade 8", "ASTM A325", "316 Stainless", "Monel", "Brighton Best 1960" };
string[] sizes = { "#1", "2", "3", "4", "5", "6", "8", "10", "12", "1/4", "5/16", "3/8", "7/16", "1/2", "9/16", "5/8", "3/4", "7/8", "1", "1-1/8", "1-1/4", "1-3/8", "1-1/2" };
var dict = new Dictionary<string, Dictionary<string, Dictionary<string, double>>>();
dict["k1"] = new Dictionary<string, Dictionary<string, double>>();
dict["k1"]["k2"] = new Dictionary<string, double>();
dict["k1"]["k2"]["k3"] = 3.5;
public Form1()
{
InitializeComponent();
}

your last attempt is close, you want:
var dict = new Dictionary<string, Dictionary<string, Dictionary<string, double>>>();
dict["k1"] = new Dictionary<string, Dictionary<string, double>>();
dict["k1"]["k2"] = new Dictionary<string, double>();
dict["k1"]["k2"]["k3"] = 3.5;
you want var instead of object
(or Dictionary<string, Dictionary<string, Dictionary<string, double>>> if you like scrolling)
and your very last string should be a double.

As I understood, you have data and want to perform lookup in it. Why can't you just use some database for that purpose?
But if you really want to hardcode all values, you can. Just don't initialize dictionary manually, make simplifications - parse data in runtime.
Something like this. (I suppose, that you are novice in c# programming, so I've created new Console Application and copy-pasted all the code for your convenience)
public class Program
{
// harcode all data as string
const string RawData =
"k11,k12,k13=3.4;" +
"k21,k22,k23=4.42;" +
"k31,k32,k33=5.91;" +
"k41,k42,k43=8.14;" +
"k51,k52,k53=4.13;" +
"k61,k62,k63=5.4";
static void Main(string[] args)
{
// create dictionary from hardcoded string
var data = ParseData();
// use Tuple as key for data lookup
var value = data[Tuple.Create("k11", "k12", "k13")];
// check, that value equals expected one
Debug.Assert(value == 3.4);
}
private static IDictionary<Tuple<string, string, string>, double> ParseData()
{
var parsedData =
RawData
.Split(';')
.Select(ParseRow)
.ToDictionary(x => x.Item1, x => x.Item2);
return parsedData;
}
private static Tuple<Tuple<string, string, string>, double> ParseRow(string row)
{
var parts = row.Split('=');
var coefficients = ParseCoefficients(parts[0]);
var value = Double.Parse(parts[1], CultureInfo.InvariantCulture);
return Tuple.Create(coefficients, value);
}
private static Tuple<string, string, string> ParseCoefficients(string row)
{
var coeffs = row.Split(',');
var result = Tuple.Create(coeffs[0], coeffs[1], coeffs[2]);
return result;
}
}
As another simplification, you can use custom class as dictionary key instead of nested dictionaries. Write your own(pay attention, that it should override equality members Equals and GetHashCode), or use something from base class library. Tuple<string, string, string> is the perfect one.

Related

List<KeyValuePair> overrides added values

I am currently facing an issue where I want to add different values to the same Key in a foreach loop.
List<KeyValuePair<string, Dictionary<string, string>>> sysList = new List<KeyValuePair<string, Dictionary<string, string>>>();
Dictionary<string, string> newSystem = new Dictionary<string, string>();
string line1="";
string line2="";
string quit="";
foreach(Worksheet ws in workbook.Worksheets)
{
while(quit != q)
{
newSystem.Clear();
line1 = Console.ReadLine();
line2 = Console.ReadLine();
quit = Console.ReadLine();
}
newSystem.Add(line1, line2);
sysList.Add(new KeyValuePair<string, Dictionary<string, string>>(ws.Name,newSystem));
}
For the first iteration (within while) of the first Worksheet ws everything is fine. If the I choose to do >1 iterations within this Worksheet, there is a new entry added, but the Dictionary values are all the same, f.e.:
syList[0]: "worksheetName","test1","test2"
syList[1]: "worksheetName","test1","test2"
syList[2]: "worksheetName","test1","test2"
If there are several foreach iterations, the names stay the same, but the Dictionary Key and Values added by newSys are the same [AFTER the second foreach iteration]:
syList[0]: "worksheetName1","test1","test2"
syList[1]: "worksheetName1","test1","test2"
syList[2]: "worksheetName1","test1","test2"
syList[3]: "worksheetName2","test1","test2"
syList[4]: "worksheetName2","test1","test2"
Initially I tried using Dictionaries, but could not handle the same keys properly and did not find a proper solution except for using List.
I am very grateful for any help provided.
If there are additional details that you require, please, let me know.
Edit:
desired result (example):
#########: ws.Name, line1, line2
syList[0]: "worksheetName1","ABC","1"
syList[1]: "worksheetName1","DEF","2"
syList[2]: "worksheetName1","ABC","5"
syList[3]: "worksheetName2","ABD","4"
syList[4]: "worksheetName2","ZZZ","1"
In case you don't want to maintain any uniqueness in the keys and just want a flat list, you can use the C#7 tuple syntax to build your list.
List<string> sheetNames = new List<string>() { "worksheetName1", "worksheetName2" };
var sysList = new List<(string SheetName, string line1, string line2)>();
string line1 = string.Empty;
string line2 = string.Empty;
string quit = string.Empty;
foreach (var sheet in sheetNames)
{
while (quit != "E")
{
line1 = Console.ReadLine();
line2 = Console.ReadLine();
quit = Console.ReadLine();
sysList.Add((sheet, line1, line2));
}
quit = string.Empty;
}
Try code below :
List<List<string>> syList = new List<List<string>>() {
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName2","test1","test2"},
new List<string>() {"worksheetName2","test1","test2"}
};
Dictionary<string, Dictionary<string, List<string>>> dict = syList
.GroupBy(x => x.First(), y => y)
.ToDictionary(x => x.Key, y => y
.GroupBy(a => a.Skip(1).FirstOrDefault(), b => b.Last())
.ToDictionary(a => a.Key, b => b.ToList()));
//using normal looping
Dictionary<string, Dictionary<string, List<string>>> dict2 = new Dictionary<string, Dictionary<string, List<string>>>();
foreach (List<string> sy in syList)
{
if (dict2.ContainsKey(sy[0]))
{
Dictionary<string, List<string>> tempDict = dict2[sy[0]];
if (tempDict.ContainsKey(sy[1]))
{
tempDict[sy[1]].Add(sy[2]);
}
else
{
List<string> newList = new List<string>() { sy[2] };
tempDict.Add(sy[1], newList);
}
}
else
{
Dictionary<string, List<string>> newDict = new Dictionary<string, List<string>>();
newDict.Add(sy[1], new List<string> { sy[2] });
dict2.Add(sy[0], newDict);
}
}

Get KeyValuePair given Key

Given a String that is a Key contained in Dictionary<String, List<String>>, how do I retrieve the KeyValuePair<String, List<String>> that corresponds to that Key?
The problem with other answers using FirstOrDefault is that it will sequentially search the entire dictionary until it finds a match, and you lose the benefit of having a hashed lookup. It seems more sensible if you really need a KeyValuePair to just build one, like this:
public class Program
{
public static void Main(string[] args)
{
var dictionary = new Dictionary<string, List<string>>
{
["key1"] = new List<string> { "1" },
["key2"] = new List<string> { "2" },
["key3"] = new List<string> { "3" },
};
var key = "key2";
var keyValuePair = new KeyValuePair<string, List<string>>(key, dictionary[key]);
Console.WriteLine(keyValuePair.Value[0]);
}
}
(with credit to David Pine for the original code in his answer).
Here's a fiddle for that: https://dotnetfiddle.net/Zg8x7s
Usually you want the value associated with the key, for example:
Dictionary<String, List<String>> dictionary = GetDictionary();
var value = dictionary["key"];
But you can use Linq to get the entire KeyValuePair:
var dictionary = new Dictionary<string, List<string>>
{
["key1"] = new List<string> { "1" },
["key2"] = new List<string> { "2" },
["key3"] = new List<string> { "3" },
};
var keyValuePair = dictionary.FirstOrDefault(kvp => kvp.Key == "key2");
Console.WriteLine(keyValuePair?.Value[0]); // Prints "2"
Here is a .NET Fiddle.

Method name expected

I have to create a json file with an array inside in c# so this is my code but throws an exception:
Method name expected
before new Dictionary<string, int>[2]();
Have you got any suggestions?
int[] lung = results.ToArray();
Dictionary<string, Dictionary<string, int>[]> padre = new Dictionary<string, Dictionary<string, int>[]>();
Dictionary<string, int>[] udemy = new Dictionary<string, int>[2]();
padre.Add("Lunghezza", udemy);
udemy[0].Add("attributo", lung[0]);
udemy[1].Add("attributo2", lung[1]);
string js = JsonConvert.SerializeObject(padre);
System.Diagnostics.Debug.WriteLine(js);
This isn't how you construct an array;
new Dictionary<string, int>[2]()
You don't need the () at all - you're not calling a method or a constructor; you're creating an array instance. Just:
new Dictionary<string, int>[2]
You'll need to populate the array as well, of course, e.g.
udemy[0] = new Dictionary<string, int>();
udemy[1] = new Dictionary<string, int>();
Using a simpler array type makes it easier to see the problem:
// Invalid
int[] x = new int[2]();
// Valid
int[] x = new int[2];
As a side note, a type of Dictionary<string, Dictionary<string, int>[]> is pretty horrible - I would strongly encourage you to redesign that to use more meaningful types.
int[] lung = results.ToArray();
Dictionary<string, Dictionary<string, int>[]> padre = new Dictionary<string, Dictionary<string, int>[]>();
Dictionary<string, int>[] udemy = new Dictionary<string, int>[2]();
// populate
udemy[0].Add("attributo", lung[0]);
udemy[1].Add("attributo2", lung[1]);
// then add
padre.Add("Lunghezza", udemy);
string js = JsonConvert.SerializeObject(padre);
System.Diagnostics.Debug.WriteLine(js);

Dictionary Manipulations in C#

I want to store the following values into a dictionary:
key (string) - values (list of strings)
aaa - myfirstvalue1
aaa - myfirstvalue2
bbb - myfirstvalue3
ccc - myfirstvalue4
ccc - myfirstvalue5
Dictionary:
Dictionary<string, List<string> myvalues = new Dictionary<string, List<string>>();
I tried to store these values but I got the duplicate key error.
Dictionaries have the feature that a key can be added only once. You have the right type, but the way you add the data matters.
You can initialize the dictionary with the data provided like this:
Dictionary<string, List<string>> myvalues = Dictionary<string, List<string>>
{
{ "aaa", new List<string> { "myfirstvalue1", "myfirstvalue2" } },
{ "bbb", new List<string> { "myfirstvalue3" } },
{ "ccc", new List<string> { "myfirstvalue4", "myfirstvalue5" } },
};
With this, each key has one list of strings assigned to it. You can add more values like this:
var key = "aaa"; // for example
if (myvalues.ContainsKey(key)
{
myvalues[key].Add("new value");
}
else
{
myvalues.Add(key, new List<string> { "new value" });
}
You can retrieve values like this:
List<string> aaaVals = myvalues["aaa"];
and then convert that List<string> to an Array with List.ToArray().

Compare two dictionaries and merge in to other dictionary with keys and values present in both dictionaries

I am working on small utility and as it turns out I have to compare two dictionaries and export the data in Excel in the below format
Key dict1value dict2value
If a key is available in both the dictionaries. My output would be
Key dict1value dict2value
If a key is available in firstdictionary and not in second . My output would be
Key dict1Value "NotAvailable"
If a key is available in second dictionary but not in first . My output would be
key "Not Available" dict2value.
To be more clear, The key column in Excel consists of keys from both the dictionaries.The value columns will have values depending on the availability.
Though the below code is working,I would like to know if I can optimize the performance even more.
Note : Please ignore the bad naming conventions
public void validateTwoDictionaries()
{
Dictionary<string, string> dict1 = new Dictionary<string, string>();
Dictionary<string, string> dict2 = new Dictionary<string, string>();
Dictionary<string, KeyValuePair<string, string>> complexdicts = new Dictionary<string, KeyValuePair<string, string>>();
dict1.Add("A", "1");
dict1.Add("B", "2");
dict2.Add("A", "2");
dict2.Add("C", "3");
dict2.Add("D", "4");
int count1 = dict1.Keys.Count;
int count2 = dict2.Keys.Count;
int maxcount = count2;
if (count1 > count2)
{
maxcount = count1;
}
for (int i = 0; i < maxcount; i++)
{
string dict1Key = string.Empty; string dict2Key = string.Empty;
//need to iterate both the dictionaries at one go.
if (i < count1)
{
dict1Key = dict1.Keys.ElementAt(i);
}
if (i < count2)
{
dict2Key = dict2.Keys.ElementAt(i);
}
// do the work for first dictionary, try to decouple to reuse for the 2nd dict
if (dict1Key != string.Empty)
{
if (!complexdicts.Keys.Contains(dict1Key))
{
if (dict2.Keys.Contains(dict1Key))
{
// Add to the complext dictionary
complexdicts.Add(dict1Key, new KeyValuePair<string, string>(dict1[dict1Key], dict2[dict1Key]));
}
else
{
complexdicts.Add(dict1Key, new KeyValuePair<string, string>(dict1[dict1Key], "Not Available"));
}
}
}
// do the work for second dictionary
if (dict2Key != string.Empty)
{
if (!complexdicts.Keys.Contains(dict2Key))
{
if (dict1.Keys.Contains(dict2Key))
{
// Add to the complext dictionary
complexdicts.Add(dict2Key, new KeyValuePair<string, string>(dict1[dict2Key], dict2[dict2Key]));
}
else
{
complexdicts.Add(dict2Key, new KeyValuePair<string, string>("Not Available", dict2[dict2Key]));
}
}
}
}
dict1 and dict2 are sample dictionaries and complexdicts object is what I want to export to excel.
Please let me know if I can do this in better way.
How about this?
Dictionary<string, string> dict1 = new Dictionary<string, string>();
Dictionary<string, string> dict2 = new Dictionary<string, string>();
Dictionary<string, KeyValuePair<string, string>> complexdicts = new Dictionary<string, KeyValuePair<string, string>>();
dict1.Add("A", "1");
dict1.Add("B", "2");
dict2.Add("A", "2");
dict2.Add("C", "3");
dict2.Add("D", "4");
var allKeys = dict1.Keys.Union(dict2.Keys);
foreach (var key in allKeys)
{
string val1;
if (!dict1.TryGetValue(key, out val1))
{
val1 = "Not Available";
}
string val2;
if (!dict2.TryGetValue(key, out val2))
{
val2 = "Not Available";
}
complexdicts.Add(key, new KeyValuePair<string, string>(val1, val2));
}
How about this?
Dictionary<string, string> dict1 = new Dictionary<string, string>();
Dictionary<string, string> dict2 = new Dictionary<string, string>();
dict1.Add("A", "1");
dict1.Add("B", "2");
dict2.Add("A", "2");
dict2.Add("C", "3");
dict2.Add("D", "4");
var allKeys = dict1.Keys.Union(dict2.Keys);
// case 1
List<Tuple<string, string, string>> unionValues = new List<Tuple<string, string, string>>();
foreach (var key in allKeys)
{
unionValues.Add(new Tuple<string, string, string>(key, dict1.ContainsKey(key) ? dict1[key] : "N/A" , dict2.ContainsKey(key) ? dict2[key] : "N/A"));
}
// case 2
var result = (from key in allKeys
select new Tuple<string, string, string>(key, dict1.ContainsKey(key) ? dict1[key] : "N/A", dict2.ContainsKey(key) ? dict2[key] : "N/A")).ToList();

Categories

Resources