Querying a Dictionary within a Dictionary with LINQ
I have a nested Dictionary like this
Dictionary<double, Dictionary<double, List<string>>>
With LINQ I would like to
Sort the outer Dictionary in descending order, 开发者_JS百科keep the first 20, and work with the inner Dictionary.
Sort the inner Dictionary in descending order, keep the sorted
List<string>
and do operations on these lists of strings.
I tried a lot of things without any success.
One long line.
var result = dict.OrderByDescending(outer => outer.Key).Take(20).SelectMany(x =>
x.Value).OrderByDescending(inner => inner.Key).Select(i => i.Value);
For testing this sort of thing, I strongly 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 lets me dump to the output with it's custom Dump() extension method (in this case I set my type to "C# Statement(s)"):
master.Keys.Dump("Master keys");
Next I get the top 2 (for your data of course you want the top 20, I just used a smaller set for testing).
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 query:
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've probably realised you could do this 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;
Last it's just a matter of what you want to do with the list, if you just want the strings in natural order per parent do this:
var stringList = from di in query
from s in di.Value
select s;
stringList.Dump("Strings only");
For my test data here's the first dozen 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
Because I was only doing the top 2 instead of top 20 I got the items for the 4.5 and 4.75 keys first, then within that I'm sorting by the second key getting all values.
Dictionaries not designed to be sorted.
Saying that, this question contains a number of different dictionary sorting strategies. How do you sort a dictionary by value?
You could use 2 SortedDictionary, and iterate over the keys, without using LINQ.
Dictionary<TKey, TValue>
implements IEnumerable<KeyValuePair<TKey, TValue>>
, allowing queries against 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;
精彩评论