Dictionary of dictionaries, how to get value? - c#

I have something like this:
private IDictionary<A, IDictionary<B, C>> data;
and I want to do something like:
IDictionary<B, C> values = new Dictionary<B, C>();
values = Data.Values;
like would I do in java, but this isn't working. I can't figure it out. Thanks for help
error:
Cannot implicitly convert type ICollection> to IDictionary

You would still call .Values, but it returns a ValueCollection, not a list. To get just the values, and not a list of Key/Value pairs, use a Select:
List<C> values = data.Values.Select(x => x.value);
http://msdn.microsoft.com/en-us/library/ekcfxy3x.aspx

If you are not sure what will come out, try to use type-inference
var coll = data.Values;
Then try to acces the Collection using a foreach-loop to access individual dictionaries.
foreach(var dic in coll){
//work on Dictionary
}
See here for a reference.

You are trying to access an ICollection of your IDictionary<B, C> which will not work since there any many Dictionaries in the Collection.
If you wish to map all the Dictionaries down then you can use a Lookup:
IDictionary<A, IDictionary<B, C>> data;
var values = data.ToLookup(d => d.Value.SelectMany(d => d.Key), d => d.Value.SelectMany(d => d.Value));
Which will give you multiple keys to multiple values.

Related

How to get Distinct keys of all child dictionary elements of all parent dictionary values

I have a dictionary like this...
Dictionary<string, Dictionary<string, double>>
How to get the list of all Distinct or unique child dictionary keys from all dictionaries of all parent dictionary values (parent dictionary values is nothing but child dictionaries)?
which is the fastest way of doing this in C#?
It's really easy using LINQ:
var result = myDict.Values.SelectMany(x => x.Keys)
.Concat(myDict.Keys)
.Distinct()
.ToList();
but even without LINQ it's super easy when you use HashSet<string>:
var set = new HashSet<string>();
foreach(var outerItem in myDict)
{
set.Add(outerItem.Key);
foreach(var innerKey in item.Value.Keys)
{
set.Add(innerKey);
}
}
HashSet<T> will only keep distinct items, so adding the same string twice won't make any difference.
PS. Next time you should try writing the code first, and ask question when you run into issue you can't overcome by yourself. Stack Overflow is not 'I want code, give me code' kind of site.
Then you need to call SelectMany() on Values property of your dictionary and then use Distinct() to get distinct elements from a sequence by using the default equality comparer.
var res = myDict.Values.SelectMany(x => x.Keys).Distinct().ToList();
This code creates a Dictionary with string keys and double values.
Dictionary<string, double> d = new Dictionary<string, double>()
{
};
// Store keys in a List
List<string> list = new List<string>(d.Keys);
// Loop through list
foreach (string k in list)
{
//From here you can choose distinct key
}
If I'm reading this right:
IEnumerable<string> uniqueChildKeys = dictOfDicts
.SelectMany(d => d.Value.Keys)
.Distinct();

Add element to a tuple outside of initialization c#

I'm new to programming, and I created a tuple list with
var tupleList = new List<Tuple<string, string>> { };
Later on in the code, I'd like to add an element like
tupleList.Add(string1,string2);
but .Add doesn't support this somehow?
Basically, I'm going through a loop and adding to the tuple and later I want to search through the tuple for a sample string, so my second question is how would I search through tupleList.Item1 and get all the pairs that equal, for example string10? I saw an answer for dictionary values, but can I do the same for tuples?
var matches = tupleList.Where(pair => pair.Item1.Equals(string10))
.Select(pair => Item2.Key);
I don't know if that makes sense though, this was the original code:
var matches = dict.Where(pair => pair.Value == "abc")
.Select(pair => pair.Key);
List<T> does not have any specific methods for working with tuples. It works with any type T. If you want to add new item to list, you should create item of list's type T and pass it to list. Adding new tuple:
tupleList.Add(Tuple.Create(string1,string2));
For searching just filter tuples list. You should not project tuples with Select operator if you want to get them as result:
var matches = tupleList.Where(pair => pair.Item1 == string10);
NOTE: I don't like tuples for their meaningless names Item1, Item2 etc, which is hard to understand. Consider creating custom class which will have properties with descriptive names.
I'd say why do the same for tuples?
If you are using a tuple to represent a key value pair, just stick to a key value pair, which is what a dictionary contains a collection of. If you model a row with more than 2 values, I'd probably favour a strongly typed model over this, where you can be more explicit in your LINQ queries.

How to get the value out of this type of dictionary in c#

I want to create, because I understand dictionaries are key=>value in C#, a dictionary that is much like key=>value(key=>value)
Currently I I know I can do:
Dictionary<int, int> someVar = new Dictionary<int, int>();
which creates me a key=>value.
To create what I want I could do (this is just a guess, please correct me if I am wrong):
Dictionary<int Dictionray<int, int>> someVar = new Dictionary<int, Dictionray<int, int>>
Now comes the fun part, I want to do ONE and only ONE for loop over this dictponary object YET get all values so it would look something like:
foreach (KeyValuePair<int, int> pair in someVar){
//object = base dictionary key
//object2 = nested dictionary key
//object3 = nested dictionary value
}
Now I come from PHP so this would be dead easy to do in one for loop. what are your ideas? because I am new to C# and the term dictionary (even though php arrays are dictionaries).
I know in C# with a for loop like this I could do: pair.Key and pair.Value.
My second part, is How do I add values to such a dictionary? I know the typical .add(bla, bla) but how do you add values to the nested part?
Iterating
In C#, IDictionary<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>>. So, you can iterate over an instance of type IDictionary<TKey, TValue> using foreach or a Linq query, and get every KeyValuePair in the data structure. Since your TValue is in this case itself an IDictionary, you can do this on the inner structure as well:
foreach(var kvp in myDictionary)
{
foreach(var innerKvp in kvp.Value)
{
var myValue = innerKvp.Value
//Logic on myValue
}
}
Using the Linq library, you can use SelectMany to get all of the KeyValuePair instances quite elegantly:
myDictionary.SelectMany(kvp => kvp.Value);
SelectMany essentially flattens a list of lists. This Linq query is saying: for each key value pair in my dictionary, get all the inner dictionaries, treat them as lists of key value pairs, and then flatten all those lists. This will return an IEnumerable<KeyValuePair<TKey, TValue>>.
If instead you only care about the values of the inner dictionary, and not the keys, you can use the Values property on IDictionary<TKey, TValue> which returns an IEnumerable<TValue> of all the values in the dictionary. We can then use SelectMany to get a list that contains all the values in the dictionary of dictionaries:
myDictionary.Values.SelectMany(dict => dict.Values);
Read more about IDictionary<TKey, TValue> here and more about KeyValuePair<TKey, TValue> here.
Adding
In order to add an element to this data structure, you'll have to first check if the inner dictionaries are null. Let's say we're trying to add 3 to the dictionary keyed by 2 in the dictionary keyed by 1:
var myInnerDictionary = myDictionary.ContainsKey(1) ? myDictionary[1] : (myDictionary[1] = new Dictionary<int, int>());
myInnerDictionary[1][2] = 3;
Of course this will override a value in that location if it already exists, so you might want to check that as well, or use the Add method, which will not overwrite.
You should also learn about the ToDictionary Linq method which can help you construct dictionaries from other IEnumerables. Read about it here.
use linq to get all the values
var values = someVar.SelectMany(x => x.Values);
as for how to add values to the nested part, you'd just need the key for the outer dictionary for which sub dictionary you want to to add it to:
someVar[key].Add(0, 0);
It's impossible to get all the values including nested by using only one foreach loop, unless nested Dictionaries have a values which you can get without using loop, like this:
foreach (var pair in someVar){
var object1 = (Dictionary<int,int>)pair.Value;
var object2 = object1[0].Value;
var object3 = object1[1].Value;
.....
// To add a values to the nested Dictionary just use Dictionary.Add method:
object1.Add(1,1);
}

C# Convert List<string> to Dictionary<string, string>

This may seem an odd thing to want to do but ignoring that, is there a nice concise way of converting a List<string> to Dictionary<string, string> where each Key Value Pair in the Dictionary is just each string in the List. i.e.
List = string1, string2, string3
Dictionary = string1/string1, string2/string2, string3/string3
I have done plenty of searching and there are literally dozens of examples on Stackoverflow alone of doing it in the opposite direction but not this way round.
The reason for doing this is I have two third part components and changing them is out of my hands. One returns a list of email addresses as a List<string> and the other send emails where the To parameter is a Dictionary<string, string>. The key of the dictionary is the email address and the value is their real name. However, I don't know the real name but it still works if you set the real name to the email address as well. Therefore why I want to convert a List to a Dictionary<string, string>. There are plenty of ways of doing this. A foreach loop on the list which adds a kvp to a dictionary. But I like terse code and wondered if there was a single line solution.
Try this:
var res = list.ToDictionary(x => x, x => x);
The first lambda lets you pick the key, the second one picks the value.
You can play with it and make values differ from the keys, like this:
var res = list.ToDictionary(x => x, x => string.Format("Val: {0}", x));
If your list contains duplicates, add Distinct() like this:
var res = list.Distinct().ToDictionary(x => x, x => x);
EDIT To comment on the valid reason, I think the only reason that could be valid for conversions like this is that at some point the keys and the values in the resultant dictionary are going to diverge. For example, you would do an initial conversion, and then replace some of the values with something else. If the keys and the values are always going to be the same, HashSet<String> would provide a much better fit for your situation:
var res = new HashSet<string>(list);
if (res.Contains("string1")) ...
Use this:
var dict = list.ToDictionary(x => x);
See MSDN for more info.
As Pranay points out in the comments, this will fail if an item exists in the list multiple times.
Depending on your specific requirements, you can either use var dict = list.Distinct().ToDictionary(x => x); to get a dictionary of distinct items or you can use ToLookup instead:
var dict = list.ToLookup(x => x);
This will return an ILookup<string, string> which is essentially the same as IDictionary<string, IEnumerable<string>>, so you will have a list of distinct keys with each string instance under it.
EDIT
another way to deal with duplicate is you can do like this
var dic = slist.Select((element, index)=> new{element,index} )
.ToDictionary(ele=>ele.index.ToString(), ele=>ele.element);
or
easy way to do is
var res = list.ToDictionary(str => str, str=> str);
but make sure that there is no string is repeating...again otherewise above code will not work for you
if there is string is repeating than its better to do like this
Dictionary<string,string> dic= new Dictionary<string,string> ();
foreach(string s in Stringlist)
{
if(!dic.ContainsKey(s))
{
// dic.Add( value to dictionary
}
}
By using ToDictionary:
var dictionary = list.ToDictionary(s => s);
If it is possible that any string could be repeated, either do a Distinct call first on the list (to remove duplicates), or use ToLookup which allows for multiple values per key.
You can use:
var dictionary = myList.ToDictionary(x => x);

Can I reference an object within a collection by it's name?

I have a Collection object (based on System.Collections.CollectionBase) but to access the values of objects within that collection, I have to use the index currently. Is it possible to get the values based on the name of the object within the collection?
For example, instead of...
MyCollection[0].Value
... how can I do something along the lines of:
MyCollection["Birthday"].Value
In order to do this you would need to have a Dictionary<string,object>. Unfortunately collections only allow random access by index.
You could do something like this:
var item = MyCollection
.Where(x => x.SomeProp == "Birthday")
.FirstOrDefault();
// careful - item could be null here
var value = item.Value;
But this will be nowhere near as efficient as random access by index.
You could use a Dictionary<TKey, TValue> which allows you to access its element by a key. So if the key in your example is a string you could use Dictionary<string, TValue>.
Why do you think objects in a collection have names? They don't. What you can do is use a Dictionary<String, SomethingElse> to enable your syntax.
As others has said, you need a Dictionary<> to do that. If you cannot change the code that provides the collection, you can use LINQ's ToDictionary() method to convert it to a dictionary yourself:
var dict = MyCollection.ToDictionary(obj => obj.Name);
From there on, you can do:
var value = dict["Birthday"].Value;
You could use the this[] accessor
public Item this[string name]
{
get
{
// iterate through the elements of the collection
//and return the one that matches with name
}
}
Have this getter property on your MyCollectionClass
One workaround could be
private const int BIRTHDAY = 0;
var value = MyCollection["Birthday"].Value;

Categories

Resources