开发者

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

  1. Sort the outer Dictionary in descending order, 开发者_JS百科keep the first 20, and work with the inner Dictionary.

  2. 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;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜