tags:

views:

321

answers:

5

Here is my problem :

I have the following dictionary :

Dictionary<double, Dictionary<double, List<string>>>;

With LINQ I would like to first

1) Sort this dictionary in descending order, keep the first 20, and work with the second dictionary.

2) With the second dictionary I would like to sort it by descending order , keep the sorted List and do operations on these lists of strings.

I tried a lot of things without any success.

Could someone put me on the right track please

Thanks

A: 

Dictionaries not designed to be sorted.

Saying that, this question contains a number of different dictionary sorting strategies. http://stackoverflow.com/questions/289/how-do-you-sort-a-c-dictionary-by-value

Alastair Pitts
A: 

You could use 2 SortedDictionary, and iterate over the keys, without using LINQ.

Mathias
Or you could just use LINQ.
Kirk Broadhurst
A: 

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;
dahlbyk
+1  A: 

One long line.

var result = dict.OrderByDescending(outer => outer.Key).Take(20).SelectMany(x =>
    x.Value).OrderByDescending(inner => inner.Key).Select(i => i.Value);
Kirk Broadhurst
A: 

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.

Timothy Walters