Query a dictionary in a dictionary with LINQ
I have a nested dictionary like this
Dictionary<double, Dictionary<double, List<string>>>
With LINQ, I would like
-
Sort the external dictionary in descending order, keep the first 20 and work with the internal Dictionary.
-
Sort the internal dictionary in descending order, keep sorted,
List<string>
and perform operations on these lists of strings.
I have tried many things with no success.
For this kind of testing, I highly recommend [LINQPad] [1], it's free for the version without autocomplete. I started by populating the data with test data:
Dictionary<double, Dictionary<double, List<string>>> master
= new Dictionary<double, Dictionary<double, List<string>>>();
for( double i = 1; i < 5; i += 0.25 )
{
master[ i ] = new Dictionary<double, List<string>>();
for( double j = 1; j < 5; j += 0.25 )
{
master[ i ][ j ] = new List<string>();
master[ i ][ j ].Add( String.Format( "{0}-{1}a", i, j ) );
master[ i ][ j ].Add( String.Format( "{0}-{1}b", i, j ) );
master[ i ][ j ].Add( String.Format( "{0}-{1}c", i, j ) );
}
}
LINQPad allows me to dump the output using a dedicated extension method Dump () (in this case, I set my type to "C # Statement (s)"):
master.Keys.Dump("Master keys");
Then I get the top 2 (for your data, of course you want the top 20, I just used a smaller test set).
var query1 = from di in master
orderby di.Key descending
select di;
query1.Take(2).Dump("Top 2 dictionaries (by key desc)");
Now I use this as the source for my next request:
var query2 = from di2 in query1.Take(2)
from item in di2.Valuefrom di in master
orderby di.Key descending
select di
orderby item.Key descending
select item;
// show output
query2.Dump("Merged list");
You probably figured out that you can do it all as one query:
var query = from di2 in (
from di in master
orderby di.Key descending
select di
).Take(2)
from item in di2.Value
orderby item.Key descending
select item;
Finally, it's just a matter of what you want to do with that list, if you just want the lines in natural order for each parent to do this:
var stringList = from di in query
from s in di.Value
select s;
stringList.Dump("Strings only");
For my test data, here are the first dozens of items I got (don't want to list all 96 results):
4.75-4.75a
4.75-4.75b
4.75-4.75c
4.5-4.75a
4.5-4.75b
4.5-4.75c
4.75-4.5a
4.75-4.5b
4.75-4.5c
4.5-4.5a
4.5-4.5b
4.5-4.5c
Since I only dealt with the top 2 and not the top 20, I first got the items for the keys 4.5 and 4.75, then in this I sort by the second key getting all the values.
source to share
Dictionaries not intended for sorting.
Having said that, this question contains a number of different word-sorting strategies. How do you sort a dictionary by value?
source to share
Dictionary<TKey, TValue>
implements IEnumerable<KeyValuePair<TKey, TValue>>
, allowing you to query your double / value pairs:
Dictionary<double, Dictionary<double, List<string>>> dict = GetDict();
IEnumerable<Dictionary<double, List<string>>> top20 = (
from kvp in dict
orderby kvp.Key descending
select kvp.Value
).Take(20);
IEnumerable<List<string>> res =
from d in top20
from kvp in d
orderby kvp.Key descending
select kvp.Value;
source to share