1

Okay, what I am trying to accomplish here is I have a dictionary with data that looks like this:

Unsorted:

US ( total population: 9 )
-New York - 4
-Miami - 5
Spain ( total population: 4 )
-Madrid - 3
-Barcelona - 1
France ( total population: 7 )
-Paris - 7

I need to sort the dictionaries by Country with largest population and then every city by largest population so it looks something like this:

Sorted:

US ( total population: 9 )
-Miami - 5
-New York - 4
France ( total population: 7 )
-Paris - 7
Spain ( total population: 4 )
-Madrid - 3
-Barcelona - 1

I have:

var worldPopulation = new Dictionary<string, Dictionary<string, long>>();

I already sorted the countries using this line of code:

worldPopulation = worldPopulation.OrderByDescending(x => x.Value.Values.Sum()).ToDictionary(x => x.Key, x => x.Value);

But I am struggling to find a solution for sorting the nested dictionary with the countries.

I am trying to do this with a single linq statement, but if its not possible a foreach solution would also be appreciated. Thanks!

EDIT:

@J_L's solution was exactly what I was looking for:

 worldPopulation = worldPopulation.OrderByDescending(x => x.Value.Values.Sum()).ToDictionary(x => x.Key, x => x.Value.OrderByDescending(y => y.Value).ToDictionary(y => y.Key, y => y.Value));

@Lucifer's solution also made it work:

var worldPopulationSorted = new Dictionary<string, Dictionary<string, long>>();

worldPopulation.OrderByDescending(dic => dic.Value.Values.Sum()).ToList().ForEach(x => worldPopulationSorted.Add(x.Key, x.Value.OrderByDescending(y => y.Value).ToDictionary(y => y.Key, y => y.Value)));

I understand that some of you are telling me to use a different approach, so will try using lists as some of you suggested. I also learned some new things, so thanks to everyone for the help.

ivan.vliza
  • 153
  • 3
  • 14
  • 8
    items order in dictionary has no meaning. Access is done by key. If you want it sorted maybe consider a different data structure. For instance instead of calling `.ToDictionary` store it in a list of tuple or so. Also have a look at [How do you sort a dictionary by value?](https://stackoverflow.com/q/289/6400526) – Gilad Green Jun 13 '18 at 12:23
  • 2
    your using the wrong collection dictionaries have not order you want a SortedList – MikeT Jun 13 '18 at 12:31
  • 2
    I would just classes here. – paparazzo Jun 13 '18 at 12:42

2 Answers2

0

Here is a working example of what you need :-

var worldPopulationSorted = new Dictionary<string, Dictionary<string, long>>();

worldPopulation.OrderByDescending(dic => dic.Value.Values.Sum()).ToList().ForEach(x => worldPopulationSorted.Add(x.Key, x.Value.OrderByDescending(y => y.Value).ToDictionary(y => y.Key, y => y.Value)));

Example which I used:-

var worldPopulation = new Dictionary<string, Dictionary<string, long>>();

Dictionary<string, long> sample = new Dictionary<string, long>();
sample.Add("1", 5);
sample.Add("2", 6);
sample.Add("3", 7);

worldPopulation.Add("first", sample);

sample = new Dictionary<string,long>();
sample.Add("3", 9);
sample.Add("2", 9);
sample.Add("1", 9);

worldPopulation.Add("second", sample);

var worldPopulationSorted = new Dictionary<string, Dictionary<string, long>>();

worldPopulation.OrderByDescending(dic => dic.Value.Values.Sum()).ToList().ForEach(x => worldPopulationSorted.Add(x.Key, x.Value.OrderByDescending(y => y.Value).ToDictionary(y => y.Key, y => y.Value)));

output:-

second
   3 - 9
   2 - 9
   1 - 9
first
   3 - 7
   2 - 6
   1 - 5

FootNote:- you really need to change the structure of your data cause if the data is in large amount then it will be really difficult to handle

Lucifer
  • 1,594
  • 2
  • 18
  • 32
  • 1
    This works, because the existing `Dictionary` returns entries in the same order you added them (unless you remove entries). Note this is an implementation detail only - Microsoft doesn't guarantee that behaviour going forward. As such, this is not recommended. – mjwills Jun 13 '18 at 13:39
  • But I don't understand the reason of down-vote this answer solves Op's req. – Lucifer Jun 13 '18 at 13:41
  • 1
    Code has contracts and implementations. The contract says 'this is what I promise - rely on this'. The implementation says 'this is how I work **right now**'. You are relying on the **implementation** when you should be relying on the contract. The docs clearly state (https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx#Anchor_7) - `For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair structure representing a value and its key. The order in which the items are returned is undefined.`. The order is undefined - you can't rely on it. – mjwills Jun 13 '18 at 13:45
  • @mjwills Now I understood what are you trying to convey, the Op here is using a Dictionary but as suggested by you guys he should be using a `SortedListt` to achieve whatever he is trying to achieve.I will edit the answer with a sorted List/dictionary solution – Lucifer Jun 13 '18 at 13:49
  • I am not convinced a `SortedList` will work either, but give it a try. – mjwills Jun 13 '18 at 13:50
  • @mjwills Considering the structure of the OP it is difficult to do so, you suggest what should I do delete the answer or let OP decide ? – Lucifer Jun 13 '18 at 14:02
0

I think this is what you are looking for:

var worldPopulation = new Dictionary<string, Dictionary<string, long>>()
{
    {"US", new Dictionary<string, long>()
    {
        { "New York", 4 },
        { "Miami", 5 }
    }},
    {"Spain", new Dictionary<string, long>()
    {
        { "Madrid", 3 },
        { "Barcelona", 1 },
    }},
    {"France", new Dictionary<string, long>()
    {
        { "Paris", 7 },
    }},
};


worldPopulation = worldPopulation.OrderByDescending(x => x.Value.Values.Sum()).
    ToDictionary(x => x.Key, 
    x => x.Value.OrderByDescending(y => y.Value).ToDictionary(y => y.Key, y => y.Value));

foreach (var country in worldPopulation)
{
    Console.WriteLine(country.Key);
    foreach (var city in country.Value)
        Console.WriteLine("   " + city.Key + " - " + city.Value);
}

Output:

US Miami - 5 New York - 4 France Paris - 7 Spain Madrid - 3 Barcelona - 1

L_J
  • 2,351
  • 10
  • 23
  • 28