I need to know how to access and initialize a series of Dictionaries containing other dictionaries.
For example, if I have
class Conv{
Dictionary<int, Dictionary<int, Dictionary<int, List<double>>>> valori;
}
And I want to initiate the parameter "valori" with random numbers, how can I do it?
I would do it like
valori[n1].Values[n2].Values[n3]
But after the first "Value", MVS gives me an error. Maybe I have to allocate the memory first? I learned a little bit of c++, but I'm still new to c#
Also let me know if I forgot something important in my question
You need to create the sub-dictionaries for each key before using them
var list = new List<double> {d};
var d1 = new Dictionary<int, List<double>> {{n3, list }};
var d2 = new Dictionary<int, Dictionary<int, List<double>>> {{n2, d1}};
valori[n1] = d2;
You can also write this short in one line:
valori[n1] = new Dictionary<int, Dictionary<int, List<double>>> {{n2, new Dictionary<int, List<double>> {{n3, new List<double> {d}}}}};
When all dictionaries are actually created you can access them normally:
var savedList = valori[n1][n2][n3];
Since this syntax is very clunky and it is easy to make a mistake (missing if a sub-dictionary exists, overriding data, etc), I'd strongly suggest changing the datastructure or at least hiding it in a dedicated class
Maybe i'm mistaken but I can't think of situation that you would need this kind of structure but nevertheless here's my help:
First of all you need to assign the variable or you will get the error :
"Use of unassign local variable".So the code will be like:
Dictionary<int, Dictionary<int, Dictionary<int, List<double>>>> valori=new
Dictionary<int, Dictionary<int, Dictionary<int, List<double>>>>();
Secondly you need to add some data to the dictionary in order to use it later so
you should do :
valori.Add(2, new Dictionary<int, Dictionary<int, List<double>>>());
valori.Add(3, new Dictionary<int, Dictionary<int, List<double>>>());
valori.Add(4, new Dictionary<int, Dictionary<int, List<double>>>());
"notice that keys are different"
And instead of new Dictionary<int, Dictionary<int, List<double>>>() you should
enter a value of that type.
Related
I'm using dictionaries in C#, and I've spent a couple of hours figuring out why my program doesn't work, and the reason is that when I manipulate a copy of a dictionary I made, then these manipulations also affect the original dictionary for some reason.
I've boiled my problem down to the following example:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Dictionary<int, List<int>> D = new Dictionary<int, List<int>>();
List<int> L1 = new List<int>(){ 1, 2, 3 };
List<int> L2 = new List<int>() { 4, 5, 6 };
D.Add(1,L1);
D.Add(2,L2);
Dictionary<int, List<int>> Dcopy = new Dictionary<int, List<int>>(D);
Dcopy[1].Add(4);
}
}
In this code, when I add an element to the list corresponding to key 1 in the copy, this element also appears in the original dictionary.
When I search online, it seem to have something to do with "reference types", and the recommended fix always seem to involve a code similar to
Dictionary<int, List<int>> Dcopy = new Dictionary<int, List<int>>(D);
which I did include in my program, but for some reason, this does not work.
Any suggestions as to why it doesn't work in my case, and any advice on what to do instead?
Best regards.
You're doing a shallow copy, instead of a deep copy. You basically need to iterate through your dictionary and create new lists
var Dcopy = new Dictionary<int, List<int>>();
foreach (var entry in D)
{
Dcopy.Add(entry.Key, new List<int>(entry.Value));
}
Or you can use the following Linq instead of the foreach
var DCopy = D.ToDictionary(entry => entry.Key, entry => new List<int>(entry.Value));
Since your lists contains int which is a value type you do not need to "clone" deeper than the lists. If instead the list contained reference types then you'd have to additionally clone them as well and possibly any reference properties all the way down.
The dictionary copy constructor makes a shallow copy of the dictionary. Since the values are lists (reference types) the lists are not cloned. If you want to make a deep copy you need to clone the values as well:
Dictionary<int, List<int>> Dcopy = D.ToDictionary(kvp => kpv.Key,
kvp => kvp.Value.ToList());
Since the values are collection of value types then there's no need to close the contents of the list - cloning the list itself is sufficient. Same for the keys - they are value types so no cloning is necessary.
If you don't need a deep copy of the lists, why not simply use .NET provided constructor, avoiding extension calls?
Dictionary<int, List<int>> Dcopy = new Dictionary<int,List<int>>(D);
I have tried reading the other posts on this subject and can't quite figure this out.
I have a list in C# that I want to put in a dictionary with all of the same keys. The list is this
string[] IN ={"Against","Like","Upon","Through","Of","With","Upon","On","Into","From","by","that","In","About","For"
,"Along","Before","Beneath","At","Across","beside","After","Though","Among","Toward","If"};
I want to create and populate a dictionary with the key being "IN" (the name of the array) and then having each string for the array in the dictionary.
This is what I wrote to create the dictionary (which I am not sure is correct):
Dictionary<string, List<string>> wordDictionary = new Dictionary<string, List<string>> ()
But I am not sure how to populate the dictionary.
Any help would be greatly appreciated as this is the first time I have tried to use a dictionary and I am new to C#
An array is string[], not List<string>, so just do this:
Dictionary<string, string[]> wordDictionary = new Dictionary<string, string[]>();
Now you can add your array as usual.
wordDictionary.Add("IN", IN);
Or:
wordDictionary.Add("IN", new string[] {"Against","Like","Upon","Through","Of","With","Upon","On","Into","From","by","that","In","About","For","Along","Before","Beneath","At","Across","beside","After","Though","Among","Toward","If"});
Dictionary.Add("IN", new List<string>(IN));
...if you want to keep the current signature for your dictionary.
If you change it to Dictionary<string, string[]> then you can just:
Dictionary.Add("IN",IN);
You currently have a string array, not a list - so it should be:
Dictionary<string, string[]> wordDictionary = new Dictionary<string,string[]> ()
Then you can just add items like:
wordDictionary.Add("IN" , IN);
Do you really need to convert your array into a string? You could very well use string[] instead of List in your dictionary:
var wordDictionary = new Dictionary<string, string[]>();
wordDictionary.Add("IN", IN);
But if you really want to convert your string array to List:
var wordDictionary = new Dictionary<string, List<string>>();
wordDictionary.Add("IN", IN.ToList());
Another way to add the array (it's not a list) to the dictionary is to use collection initializer:
var wordDictionary = new Dictionary<string, string[]> { "IN", IN };
This is exactly the same as creating the dictionary in a normal way and then calling Add("IN", IN).
var for_cat_dict = new Dictionary<string, string>();
var category_Dict = new Dictionary<string,Dictionary<string,string>>();
for_cat_dict.Add(bean.getId(), bean.getId());
Now I want to add elements to the category_dict. So I tried..
category_Dict.Add(bean.getId(),[for_cat_dict]);
But it doesnt work... any solutions??
It's not really clear what you're trying to do, but
Category_Dict.Add(bean.getId(), for_cat_dict);
should at least compile. Whether it'll do what you want is another matter - it's not clear whether these are local variables, fields etc. (It also looks like you're not following .NET naming conventions in various ways...)
Dictionary<string, string> for_cat_dict = new Dictionary<string, string>();
Dictionary<string, Dictionary<string, string>> Category_Dict = new Dictionary<string, Dictionary<string, string>>();
Category_Dict.Add("somekey", for_cat_dict);
Hey Guys, I'm trying to add to a dictionary, and recieveing the "Object reference not set to an instance of an object." error. Which I think means that what I'm trying to set it to doesn't exist?
This is the relevant code:
Dictionary<string, Dictionary<int, Dictionary<string, string>>> user = new Dictionary<string, Dictionary<int, Dictionary<string, string>>>();
user.Add("approved", null);
user.Add("pending", null);
user.Add("declined", null);
int zz = 0;
while (results.Read())
{
Dictionary<string, string> field = new Dictionary<string, string>();
for (int i = 0; i < results.FieldCount; i++)
{
switch (fds[i].ToString())
{
case "gender":
string gend = ((Convert.ToBoolean(results[i])) == false) ? "Male" : "Female";
field.Add("gender", gend);
break;
default:
field.Add(fds[i], results[i].ToString());
break;
}
}
string status = results[0].ToString();
user["approved"].Add(zz, field);
zz++;
}
Is there an issue with the way I am setting the three dictionaries at the beginning?
Thanks,
Psy
You have a third level in your nested dictionary structure, and you're skipping initialization of the second level. At the very least, you need to add:
user["approved"] = new Dictionary<int, Dictionary<string, string>>();
What would probably be better, is to do initialization further up front:
user.Add("approved", new Dictionary<int, Dictionary<string, string>>());
user.Add("pending", new Dictionary<int, Dictionary<string, string>>());
user.Add("declined", new Dictionary<int, Dictionary<string, string>>());
Personally, I wouldn't use a Dictionary for user at all. It implies that there are a variable number of statuses of a request (or whatever), while in fact there is a finite amount of possibilities: pending, approved, declined. In my opinion, you would be better off writing a class that holds 3 collections for that.
This also helps in that you wouldn't have three nested Dictionaries, making the code more readable. It was enough to confuse you, let alone someone maintaining the code after you :)
You never create a Dictionary<int, Dictionary<string, string>> object, so in the line of code:
user["approved"].Add(zz, field); // user["approved"] is null
user is a dictionary mapping strings to a dictionary (the details of which aren't important for our purposes). The line
user.Add("approved", null);
adds an entry to user mapping "approved" to the null dictionary. You never set the dictionary that "approved" is mapped to a non-null dictionary so that when you hit the line
user["approved"].Add(zz, field);
you are trying to invoke the method Dictionary.Add on a null dictionary. You can fix this by adding the line
user["approved"] = new Dictionary<int, Dictionary<string, string>>();
The same applies to the other two entries in user.
What about:
user["approved"] = field;
The line:
user["approved"].Add(zz, field);
bangs with a NullReferenceException because when you access user["approved"] it returns null because it's not initialized.
I would like to use Dictionary as TKey in another Dictionary. Something similar to python. I tried this but it gives me errors.
Dictionary<Dictionary<string, string>, int> dict = new Dictionary<Dictionary<string, string>, int>();
Dictionary<string, string> dict2 = new Dictionary<string, string>();
dict2["abc"] = "def";
dict[dict["abc"] = 20;
What error is it giving you? Is it complaining about your missing bracket on line 4?
Line 4 looks like it should be:
dict[dict["abc"]] = 20;
However, you probably mean this, since "abc" is not a key of dict:
dict[dict2["abc"]] = 20;
But dict2["abc"] is a string, when the key of dict is supposed to be a Dictionary<string, string>.
But let's re-examine your original goal at this point before going to far down this path. You shouldn't be using mutable types as dictionary keys in the first place.
This may be the code you're looking for:
Dictionary<string, int> dict = new Dictionary<string, int>();
Dictionary<string, string> dict2 = new Dictionary<string, string>();
dict2["abc"] = "def";
dict[dict2["abc"]] = 20;
But it's hard to tell for sure.
Just to throw this in there, I often find that dealing with complicated dictionaries like you describe it's far better to use real names with them rather than trying to let the reader of the code sort it out.
You can do this one of two ways depending on personal preference. Either with a using statement to create a complier alias. Note you have to use the fully qualified type name since this is a compiler alias.
using ComplexKey = System.Collections.Generic.Dictionary<String, String>;
using ComplexType = System.Collections.Generic.Dictionary<
System.Collections.Generic.Dictionary<String, String>,
String
>;
Or you can go the full blown type way and actually create a class that inherits from Dictionary.
class ComplexKey : Dictionary<String, String> { ... }
class ComplexType : Dictionary<ComplexKey, String> { ... }
Doing this will make it far easier for both you and the reader of your code to figure out what you're doing. My general rule of thumb is if I'm creating a generic of a generic it's time to look at building some first class citizens to represent my logic rather.
It's because the "dict["abc"] is not dictionary, but "string".
The correct, what you asked is:
Dictionary<Dictionary<string, string>, int> dict = new Dictionary<Dictionary<string, string>, int>();
Dictionary<string, string> dict2 = new Dictionary<string, string>();
dict2["abc"] = "def";
dict[dict2] = 20;
But i'm not sure, this is what you realy want/need.