Monday, July 30, 2018

Compare keys of dictionary with values of another dictionary

Leave a Comment

I have two dictionaries, both of type Dictionary<string, List<List<string>>. I want to select the range of entries from dictionary 1 which match the values/entries from dictionary 2.

E.g. dictionary 1 has the keys 01, 01.1 and dictionary 2 has the matching values 01, 01.1. at key 1

First I get the entries from dictionary 2 at key 1 like this:

var dictList = (from entry in DbDict                 where entry.Key == id.ToString() // id = 1                 select entry).ToList(); 

I tried to select these via linq with something like this:

var matchingEntries = (from entry in ExcelDict                        where ExcelDict.Keys.Equals(dictList[0].Value)                        select entry).ToList(); 

and tried more along those lines, but it won't return any results.

How do I get the range of valuepairs from dictionary 1, whose keys match the values of dictionary 2?

Edit1:

Dictionary 1:  Key     Value 01      "these", "are"         ..., ... 01.1    "just", "some"         ..., ... 02      "sample", "values"         ..., ...  Dictionary 2: Key     Value 1       "01", "01.1"         "foo", "bar"         ..., ...                 2       "02", "02.21"         "value1" "value2" 

Edit2:

Expected output:

"01", "01.1" "foo", "bar" 

Edit3:

Compilable input as requested in the comments. This is exactly the structure I'm dealing with:

var dict1 = new Dictionary<string, List<List<string>>>();  dict1.Add("01", new List<List<string>> { new List<string> { "these" }, new List<string> { "are" } }); dict1.Add("01.1", new List<List<string>> { new List<string> { "just" }, new List<string> { "some" } }); dict1.Add("02", new List<List<string>> { new List<string> { "sample" }, new List<string> { "values" } });   var dict2 = new Dictionary<string, List<List<string>>>(); dict2.Add("1", new List<List<string>> { new List<string> { "01", "01.1" }, new List<string> { "foo", "bar" } }); dict2.Add("2", new List<List<string>> { new List<string> { "02", "value1" }, new List<string> { "02.21", "value2" } }); 

3 Answers

Answers 1

You wrote:

I want to select the range of entries from dictionary 1 which match the values/entries from dictionary 2.

From your output in Edit2, it seems that you want to take the values in Dictionary 2. You don't do anything with the Keys. Each value is a List>. In your example the all strings in the first list of the value with Key 1 have a corresponding key in dictionary 1. Therefore the complete value is in your output

The first list of the value with Key 2 has an element which is not a key in dictionary 1. Hence nothing of the value is in the output.

Unclear: what if the 2nd list would match instead of the 1st list?

Key     Value 3       "foo", "bar"         "01", "01.1" 

Should this also be in your final result?

Unclear Do you want as result a List>, or do you want one big list with all matching values? What abut duplicates?

Let's assume you only want to check the first List in your List of Lists:

We'll only look at the values from Dictionary 2, the keys are discarded. Then from every list in this value collection we take the first one (if there is one), and as a separate property remember the complete list.

Of course if the list is empty is should not be in the end result, hence we keep only those that have a first element:

IEnumerable<List<List<string>>> dict2Values = dictionary2     .Select(keyValuePair => keyValuePair.Value);  var separatedFirstList = dict2Values.Select(listOfLists=> new {      FirstList = listOfLists.FirstOrDefault(), // this is a List<string>      AllLists = listOfLists,                   // List<List<string>> where FirstList is the first }) .Where(stringListWithFirstElement => stringListWithFirstElement.FirstList != null); 

By now we have transformed your dictionary into:

{     FirstString = {"01", "01.1"},     FullList =    {"01", "01.1"}, {"foo", "bar"}, {...}, {...}, }, {     FirstString = {"02", "02.21"},     FullList =    {"02", "02.21"}, {"value1" "value2"}, ... }, {      FirstString = ...,      FullList = ..., }, ... 

From this sequence we only want to keep those WHERE ALL elements in the FirstString are keys of Dictionary 1:

IEnumerable<string> keysDictionary1 = dictionary1.Keys; var matchingItems = separatedFirstList     .Where(item => item.FirstList.All(txt => keysDictionary1.Contains(txt)); 

You see the Where and the All.

Result:

{     FirstString = {"01", "01.1"},     FullList =    {"01", "01.1"}, {"foo", "bar"}, {...}, {...}, }, ... 

The one with FirstString = {"02", "02.21"} is removed, because not all elements of firstString where a Key in dictionary 1,

Finally: get rid of the FirstString:

List<List<String>> finalResult = matchingItems.Select(matchingItem => matchingItem.FullList); 

Or if you want as a result one List<String>:

List<string> finalResult = matchingItems.SelectMany(matchingItem => matchingItem.FullList); 

Answers 2

It seems you are looking for join using linq:

var result = from d1 in dict1              join d2 in dict2              on double.Parse(d1.Key) equals double.Parse(d2.Key)              select d2.Value; 

In above query, we are joining two dictionaries by equality of key (by parsing the key as number) and for each match we select the Value from the second dictionary as result of the match.

Answers 3

This will give you what you want:

var result = dict2             .Select(kvp => kvp.Value)             .Where(list => list.Where(l => l.Join(dict1.Keys, s1 => s1, s2 => s2, (s1, s2) => s1).Count() == l.Count).Count() > 0)             .ToList(); 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment