0

I am trying to sort a dictionary within a dictionary. My goal is to sort the 'sub' dictionary ['extra'] based on it's values, from high to low.The problem I'm having is that my 'sub' dictionary is nested deep within the main dictionary. Using other examples, I can do this for one level higher, see my code below. So instead of sorting 'marks', I would like to sort the items 1,2 & 3 based on their values. Code:

# initializing dictionary
test_dict = {'Nikhil' : { 'roll' : 24, 'marks' : 17, 'extra' : {'item1': 2, 'item2': 3, 'item3': 5}},
             'Akshat' : {'roll' : 54, 'marks' : 12, 'extra' : {'item1': 8, 'item2': 3, 'item3': 4}}, 
             'Akash' : { 'roll' : 12, 'marks' : 15, 'extra' : {'item1': 9, 'item2': 3, 'item3': 1}}}
  
# printing original dict
print("The original dictionary : " + str(test_dict))
  
# using sorted()
# Sort nested dictionary by key
res = sorted(test_dict.items(), key = lambda x: x[1]['marks'])

# print result
print("The sorted dictionary by marks is : " + str(res))

# How to sort on 'extra'? 

So this is what I want it to look like:

sorted_dict = {'Nikhil' : { 'roll' : 24, 'marks' : 17, 'extra' : {'item3': 5, 'item2': 3, 'item1': 2}},
             'Akshat' : {'roll' : 54, 'marks' : 12, 'extra' : {'item1': 8, 'item3': 4, 'item2': 3}}, 
             'Akash' : { 'roll' : 12, 'marks' : 15, 'extra' : {'item1': 9, 'item2': 3, 'item3': 1}}}
CrossLord
  • 574
  • 4
  • 20
  • 1
    While dictionaries remain in insertion order in recent Python versions, it is still best practice to use a type with real order. Consider using a list of a `collections.OrderedDict`. – Klaus D. Jul 29 '21 at 10:34
  • @KlausD. do you have some examples of that? – CrossLord Jul 29 '21 at 13:00
  • No it's about the order of the items *item1, item2, item3) in the sorted_dict: they are sorted from largest to smallest. That's not the case for the test-dict. The question is how to do this. – CrossLord Jul 31 '21 at 11:00
  • Wait... you don't want to change the *order* in which `item1`, `item2`, `item3` appear, but you want to change which *values* are associated with them? Why do you not have a list then? Like `'extra': [5, 3, 2]`? – mkrieger1 Jul 31 '21 at 11:15
  • No it's about the order, and then see what number/value is associated with it. I want to see the key (item1/2/3) and it's associated value, but just order from largest to smallest. In my 'real' example I have sometimes item1 up untill ... item20, and I want to have the ones with the largest value first, since these are more relevant – CrossLord Jul 31 '21 at 11:18
  • But you have shown that you want to change `{'item1': 2, 'item2': 3, 'item3': 5}` to `{'item1': 5, 'item2': 3, 'item3': 2}`, not to `{'item3': 5, 'item2': 3, 'item1': 2}`. – mkrieger1 Jul 31 '21 at 11:22
  • Ah that's my bad! Sorry for the confusion I change it right away – CrossLord Jul 31 '21 at 11:44

4 Answers4

1

Well this seems to do it:

test_dict = {
    'Nikhil': {'roll': 24, 'marks': 17, 'extra': {'item1': 2, 'item2': 3, 'item3': 5}},
    'Akshat': {'roll': 54, 'marks': 12, 'extra': {'item1': 8, 'item2': 3, 'item3': 4}}, 
    'Akash':  {'roll': 12, 'marks': 15, 'extra': {'item1': 9, 'item2': 3, 'item3': 1}}
}

sorted_dict = test_dict.copy()
for name in test_dict:
    extra = test_dict[name]['extra']
    sorted_extra = dict(reversed(sorted(extra.items(), key=lambda item: item[1])))
    sorted_dict[name]['extra'] = sorted_extra
CrossLord
  • 574
  • 4
  • 20
0

this sorts the values but not the keys of the 'extra' dict for all dicts in the big dictionary:

test_dict = {
    'Nikhil': {'roll': 24, 'marks': 17, 'extra': {'item1': 2, 'item2': 3, 'item3': 5}},
    'Akshat': {'roll': 54, 'marks': 12, 'extra': {'item1': 8, 'item2': 3, 'item3': 4}}, 
    'Akash':  {'roll': 12, 'marks': 15, 'extra': {'item1': 9, 'item2': 3, 'item3': 1}}
}

for dct in test_dict.values():
    extra_keys, extra_values = dct['extra'].keys(), dct['extra'].values()
    dct['extra'] = dict(zip(extra_keys, sorted(extra_values, reverse=True)))

print(test_dict)

output:

{'Nikhil': {'roll': 24, 'marks': 17, 'extra': {'item1': 5, 'item2': 3, 'item3': 2}},
 'Akshat': {'roll': 54, 'marks': 12, 'extra': {'item1': 8, 'item2': 4, 'item3': 3}},
 'Akash': {'roll': 12, 'marks': 15, 'extra': {'item1': 9, 'item2': 3, 'item3': 1}}}
Kesslwovv
  • 639
  • 4
  • 17
0

Same thing can also be achived by List Comprehension

test_dict = {
    'Nikhil': {'roll': 24, 'marks': 17, 'extra': {'item1': 2, 'item2': 3, 'item3': 5}},
    'Akshat': {'roll': 54, 'marks': 12, 'extra': {'item1': 8, 'item2': 3, 'item3': 4}}, 
    'Akash':  {'roll': 12, 'marks': 15, 'extra': {'item1': 9, 'item2': 3, 'item3': 1}}
}

result = {
  k: {
    m: dict(sorted(n.items(), reverse=True, key=lambda x: x[1]))
    if m == 'extra' else n
    for (m, n) in v.items()
  } for (k, v) in test_dict.items()
}

print(result)
Chandan
  • 11,465
  • 1
  • 6
  • 25
0

sort the inner dict and assign it to test_dict[key]['extra'].. just with a loop

for key in test_dict.keys():
    test_dict[key]["extra"] = dict(sorted(test_dict[key]["extra"].items(), key=itemgetter(1), reverse=True))

than the test_dict output would be as

{
 'Nikhil': {'roll': 24, 'marks': 17, 'extra': {'item3': 5, 'item2': 3, 'item1': 2}}, 
 'Akshat': {'roll': 54, 'marks': 12, 'extra': {'item1': 8, 'item3': 4, 'item2': 3}}, 
 'Akash': {'roll': 12, 'marks': 15, 'extra': {'item1': 9, 'item2': 3, 'item3': 1}}
}
Ali Aref
  • 1,893
  • 12
  • 31