Fastest of the following Mapping objects (Dictionary,Tuple,KeyvaluePair) - c#

Currently i have a mapping setup like this
//Identifiers to save (currently)
Dictionary<string, Dictionary<string, string>> toSaveIdentifiers =
new Dictionary<string, Dictionary<string, string>>(); //
however, i want to add an extra dimension to it because i just missed out on an extra attribute to add.
I'm trying to set up some form of mapping that gets populated frequently in a program and is looked up throughout the program as well. I was wondering what is the best way to go about doing this.
//Identifiers to save (tuple)
Dictionary<Tuple<string,string>, Dictionary<string, string>> toSaveIdentifiers =
new Dictionary<Tuple<string, string>, Dictionary<string, string>>(); //
//Identifiers to save (adding another dictionary dimension)
Dictionary<string, Dictionary<string,Dictionary<string, string>>> toSaveIdentifiers =
new Dictionary<string, Dictionary<string, Dictionary<string, string>>>(); //
//Identifiers to save (adding keyvaluepair)
Dictionary<KeyValuePair<string,string>, Dictionary<string, string>> toSaveIdentifiers =
new Dictionary<KeyValuePair<string, string>, Dictionary<string, string>>(); //
When i populate it/lookup i do something like.
// check identifier map dictionary
if (dictionary.Keys.Contains(identifier))
{
if (dictionary[identifier].Keys.Contains(currency))
{
//stuff
}
else
{
//stuff
}
}
else
{
//more stuff
}
What would be the best method of doing this for lookup?

Since your identifiers all seem to be of type string, you could always just concat them all into one big string and use that as the key. Then instead of doing the nested Contains, you'd just have to do one. It'd also be more flexible as far a storing different levels of identifiers.
i.e. Given a 2 level key, it'd be
string ident = level1Identifier + "." + level2Identifier;
(using string.format() or StringBuilder would be more efficient, but this code is better for explaining)
Also consider the joining character should be something you know won't show up in any levels identifier to avoid confusion or accidently duplicates.

Related

How can I map multipul lists to one key on C#?

I need to map one string (sentence) in to two lists (similar sentences indexes and the different word in each one).
By using "Dictionary" I have to use 2 dictionaries to save each list.
Is there other way to save a string as a key to int[] and string[]?
this is how it lookes now:
Dictionary<string, int[]> similarSentences = new Dictionary<string, int[]>();
Dictionary<string, string[]> changes = new Dictionary<string, string[]>();
I want someting like this:
Dictionary<string, int[],string[]> similarSentencesAndChanges = new Dictionary<string, int[],string[]>();
Thank you!
You could use tuples:
Dictionary<string,(int[] Similar, string[] Changes)> similarSentencesAndChanges = new Dictionary<string,(int[] Similar, string[] Changes)>();
and then you can access it like this:
var someKey = "somekey";
(int[] similar, string[] changes) = similarSentencesAndChanges[someKey];
However, depending on what you plan to do, randomly using tuples is a bad practice and you'd be wise in creating a class that contains both collections.
class SentenceData
{
public int[] Similar {get;}
public string[] Changes {get;}
}
Then, make your dictionary of type Dictionary<string, SentenceData>.
This has the added benefit of allowing the reuse of the object in other parts of your code. Furthermore, adding properties to the object at a latter stage won't involve potentially rewriting large parts of your code.
Assuming you are ok to use tuples, you could create an extension method for the generic Dictionary<TKey, TValue> type, which returns a dictionary with tuple values...
public static Dictionary<TKey, (TValue, TValue2)> Combine<TKey, TValue, TValue2>(this Dictionary<TKey, TValue> a, Dictionary<TKey, TValue2> b)
{
return a.Keys.Union(b.Keys).ToDictionary(x => x, x => (
a.ContainsKey(x) ? a[x] : default,
b.ContainsKey(x) ? b[x] : default
));
}
Example usage...
var similarSentencesAndChanges = similarSentences.Combine(changes);

C# Tuple Dictionary

I am trying to expand my usage of the dictionary and want to have multiple values for my pairs.
I have had no issues with adding items to the dictionary with one .
I have tried to use Tuple as an option but cant seem to figure out how to extract a particular value.
this works:
Dictionary<string, string> voc4 = new Dictionary<string, string>();
voc1.Add(key1, value);
if (voc1.TryGetValue(result.Text.ToLower(), out string cmd))
{
ToSend(cmd);
}
I tried to build a new dictionary with Tuple:
Dictionary<string, Tuple<string ,string>> voc5 = new Dictionary<string,Tuple<string ,string>>();
voc5.Add(key1, new Tuple<string, string>(value,response));
if (voc5.TryGetValue(result.Text.ToLower(), out string cmd))
{//this is what I cant get working. I want to get the first value of thedictionary for 1 purpose and the other for a different purpose
}
How can I get certain values based on the key and use them for different functions?
example would be:
if (voc5.TryGetValue(result.Text.ToLower(), out string cmd))// the first value
{
ToSend(value 1 from tuple).ToString();
ToDisplay(value 2 from tuple).ToString();
}
Any help would be great
You can only get the entire Tuple<string, string> instance out of your dictionary. Even if you'd only like to use one of the values, you have to fetch the entire tuple out.
After you retrieve the tuple use ItemN to access the elements.
if (voc5.TryGetValue(result.Text.ToLower(), out Tuple<string, string> cmd))
{
ToSend(cmd.Item1).ToString();
ToDisplay(cmd.Item2).ToString();
}

How to make deep copy of a dictionary within Dictionary in c#? [duplicate]

This question already has answers here:
What is the best way to clone/deep copy a .NET generic Dictionary<string, T>?
(14 answers)
Closed 9 years ago.
I have four Dictionary , two are (dictionary within Dictionary), declaration shown below
Dictionary<string, Dictionary<string, string>> dict_set = new Dictionary<string, Dictionary<string, string>>();
Dictionary<string, Dictionary<string, string>> dict_Reset = new Dictionary<string, Dictionary<string, string>>();
Dictionary<string, string> set_value = new Dictionary<string, string>();
Dictionary<string, string> Reset_value = new Dictionary<string, string>();
I want to first add elements in dictionary set_vlaue and Reset_value.
once the values are added then i am adding these dictionaries to other two dictionaries as shown below.
dict_set.Add(condiName, set_value);
dict_Reset.Add(condiName, Reset_value);
set_value.Clear();
Reset_value.Clear();
the values are getting added , but after adding set_value and reset_value dictionaries , i want to clear these two dictionaries set_value and reset_value,but problem occurs that when set_value and reset_value are cleared the data from dict_set and dict_reset is also cleared..
can any one help me , to how to create deep copy of dictionaries in this case...
I do not know what you are trying to do in the workflow, but why not to reinstancing instead of cleaning?
dict_set.Clear();
to:
dict_set = new Dictionary<string, string>();
Aside of what Skeet has written in the answer pointed out by keyboardP, in most managed languages you may very easily perform deep copy by:
serializing the thing
deserializing it back
Upon deserialization, you'll usually have a complete deep clone of the original. The serializer will usually do all the ID-checking, breaking cycles, deduplicating, etc. In your case this is not necessary, but it may came handy later.
You may serialize it to XML, BinaryForm, JSON or whatever you like and have at hand. It is not that important.
Now back to your question:
This is your code, just shortened a bit:
var dict_set = new Dictionary<string, Dictionary<string, string>>();
var dict_Reset = new Dictionary<string, Dictionary<string, string>>();
var set_value = new Dictionary<string, string>();
var Reset_value = new Dictionary<string, string>();
dict_set.Add(condiName, set_value);
dict_Reset.Add(condiName, Reset_value);
set_value.Clear();
Reset_value.Clear();
You claim that:
(...) but problem occurs that when set_value and reset_value are cleared the data from dict_set and dict_reset is also cleared..
This is not true. With that code of above, it is not possible. set/reset/dict_set/dict_reset are 4 distinct objects. Calling "Clear" on "set/reset" cannot cause the others to be cleared.
Look at your code. The error is elsewhere. Not here. Something other is clearing that dict* dictionaries.
By creating new instance will solve the above issue.. if any one came across some other better solution please post..
dict_set.Add(condiName, new Dictionary<string, string>(set_value));
dict_Reset.Add(condiName, new Dictionary<string, string>(Reset_value));
set_value.Clear();
Reset_value.Clear();
I think this way the inner dictionaries in dict_set and dict_Reset will not be cleared
dict_set.Add(condiName, set_value.ToDictionary(entry => entry.Key,entry => entry.Value));
dict_Reset.Add(condiName, Reset_value.ToDictionary(entry => entry.Key,entry => entry.Value));
set_value.Clear();
Reset_value.Clear();
With the ToDictionary() method you actually create a new Dictionary object, not using the reference to tour originals dictionaries anymore, so you can safely clear them.
Adding and removing data to the set_value and Reset_value alsdo does not affect the dictionaries inside dict_set and dict_Reset
Just out of curiousity, why Reset_value with a capital S and set_value not?

Setting value in jagged dictionary sets all values

I have a jagged dictionary:
Dictionary<string, Dictionary<int, Dictionary<string, string>>> tierOptions = new Dictionary<string, Dictionary<int, Dictionary<string, string>>>();
Later on, I have code that sets one of those values in the array:
tierOptions[optionID][npID]["tName"] = cboTier.Text;
The problem is that when it runs through this portion of code, all "tName" elements are set to cboTier.Text instead of just the one element.
For instance if optionID was 1 and npID was 8, and I had these three:
tierOptions[1][8]["tName"]
tierOptions[2][8]["tName"]
tierOptions[3][8]["tName"]
That particular line of code would set all three, instead of just tierOptions[1][8]["tName"]
Any idea why it is doing this? Thanks!
It sounds simply like you have used the same dictionary instance in several "dimensions" (your terminology). Since this is a reference, they are all shared (there is no automatic clone-into-isolated-copies here).
When filling the data, take care to use isolated dictionary instances when the data should be separate.
Yep, I would say the sae as Marc.
Please take a look at this example how you can retreive the vlaue from your type of Dictionary:
Dictionary<string, Dictionary<int, Dictionary<string, string>>> dic = new Dictionary<string, Dictionary<int, Dictionary<string, string>>>();
//add to 1st dic:
dic.Add("A", new Dictionary<int, Dictionary<string, string>>());
//add to 2nd dic:
dic["A"].Add(1, new Dictionary<string, string>());
//add to 3rd dic:
dic["A"][1].Add("a", "value 1");
//string KeyIn3rdDic = dic["A"][1].ToString();
string ValueIn3rdDic = dic["A"][1]["a"]; //result is "value 1";

C# dictionary pattern, which is best?

Which of these patterns should be preferred over the other and why?
foreach(KeyValuePair<string, Dictionary<string, string>> data in
new Dictionary<string, Dictionary<string, string>> {
{"HtmlAttributes", this.HtmlAttributes},
{"Content", this.Content}
})
{
foreach(KeyValuePair<string, string> entry in data.Value)
{
// do something
}
}
or
Dictionary<string, Dictionary<string, string>> data = new Dictionary<string, Dictionary<string, string>>();
data.Add("HtmlAttributes", this.HtmlAttributes);
data.Add("Content", this.Content);
foreach(KeyValuePair<string, IDictionary<string, string>> entry in data)
{
// Do something
}
data.Clear(); // not sure if this is needed either
data = null; // gc object
Please don't answer with "use var", as I don't like using it.
Re: var (2 years later): I must add something to make this right. In retrospect, reading Eric Lipert's blog post about when and why to use var makes total sense. IF used appropriately, meaning not all the time, it makes perfect sense and it shortens the amount code one needs to read. On the matter of what initialization to use, well the object initializer is fine, but splitting up initialization from the foreach or other processing makes the code more readable.
I think the comments by Kent Boogaart and quakkels are right. var makes sense here. If I had to choose one of your two I'd say the 2nd is better as it's slightly easier to read.
I would prefer something in between your two versions: split creation and iteration, but use collection initializer.
Dictionary<string, Dictionary<string, string>> dicts =
new Dictionary<string, Dictionary<string, string>> {
{"HtmlAttributes", this.HtmlAttributes},
{"Content", this.Content}
});
foreach(KeyValuePair<string, Dictionary<string, string>> data in dicts)
{
foreach(KeyValuePair<string, string> entry in data.Value)
{
// do something
}
}
or equivalently (really, from the point of view of both the compiler and IDE, the following is exactly the same):
var dicts = new Dictionary<string, Dictionary<string, string>> {
{"HtmlAttributes", this.HtmlAttributes},
{"Content", this.Content}
});
foreach(var data in dicts)
{
foreach(var entry in data.Value)
{
// do something
}
}
Also, if you're using Dictionary just as a list of pairs, you could use either List<KeyValuePair<K, V>> or (on .Net 4) List<Tuple<T1, T2>>.
I think your second version is more readable. Given that you don't like to use var, that seems even more important as your first version kind of gives me a headache.
I also think that it's a little convoluted to mix the code that creates a collection with the code that loops through it.
So, for me, it's a matter of readability and I prefer the second version. But in the end, either one works.

Categories

Resources