Python Forum
sorting nested dict according to values
Thread Rating:
  • 1 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
sorting nested dict according to values
#1
What I have: a nested dict (see code), with integer values as lowest "level".
What I wish to reach: a couple of lists with pairs of the highest level key and the values, while the intermediate keys are 'transformed' in the name of each list. The last part is done manually. (In the output, the order of the lists among each other is not relevant, only the order of the list items.)

My code actually is something like:
import operator

dict_to_sort = {"key1": {"subkey1": {"subsubkey1": 1,
                                      "subsubkey2": 9},
                         "subkey2": {"subsubkey1": 4,
                                      "subsubkey2": 24},
                          "subkey3": {"subsubkey1": 5,
                                      "subsubkey2": 7}},
                "key2": {"subkey1": {"subsubkey1": 12,
                                      "subsubkey2": 4},
                         "subkey2": {"subsubkey1": 226,
                                      "subsubkey2": 17},
                          "subkey3": {"subsubkey1": 3,
                                      "subsubkey2": 3}},
                "key3": {"subkey1": {"subsubkey1": 8,
                                      "subsubkey2": 11},
                         "subkey2": {"subsubkey1": 105,
                                      "subsubkey2": 10},
                          "subkey3": {"subsubkey1": 9,
                                      "subsubkey2": 10}}}

##desired output:
##subkey3subsubkey1: [['key3', 9], ['key1', 5], ['key2', 3]]
##
##subkey1subsubkey1: [['key2', 12], ['key3', 8], ['key1', 1]]
##
##subkey2subsubkey2: [['key1', 24], ['key2', 17], ['key3', 10]]
##
##subkey1subsubkey2: [['key3', 11], ['key1', 9], ['key2', 4]]
##
##subkey3subsubkey2: [['key3', 10], ['key1', 7], ['key2', 3]]
##
##subkey2subsubkey1: [['key2', 226], ['key3', 105], ['key1', 4]]


klist = ["subkey1subsubkey1", "subkey1subsubkey2", "subkey2subsubkey1",
         "subkey2subsubkey2", "subkey3subsubkey1", "subkey3subsubkey2"]
listdict = {}

for lii in klist:
    listdict[lii] = []

for tup in [["subkey1subsubkey1", "subkey1", "subsubkey1"],
            ["subkey1subsubkey2", "subkey1", "subsubkey2"],
            ["subkey2subsubkey1", "subkey2", "subsubkey1"],
            ["subkey2subsubkey2", "subkey2", "subsubkey2"],
            ["subkey3subsubkey1", "subkey3", "subsubkey1"],
            ["subkey3subsubkey2", "subkey3", "subsubkey2"]]:
    for keynum in dict_to_sort.keys():
        listdict[tup[0]].append([keynum, dict_to_sort[keynum][tup[1]][tup[2]]])

for liik in listdict.keys():
    sorted(listdict, key = operator.itemgetter(1), reverse = True)
    print("\n" + liik + ": " + str(listdict[liik]))


The sorting doesn't work in this way. As far as I can say, the order of the keys in the result lists is arbitrary. But how to use the itemgetter (or something else) to sort the listdict by the second list item then?

And I wonder whether there would be a more straight way to achieve my goal?
Reply
#2
To sort a list of lists by the second item in the sublist:
list_of_lists.sort(key = lambda x: x[1])
The key parameter is a function that returns the value to sort by when given a value to be sorted.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#3
Your main problem (beside sorted not sorting in place) is that you are sorting different thing than you want.

for liik in listdict.keys():
    sorted(listdict, key = operator.itemgetter(1), reverse = True)
    print("\n" + liik + ": " + str(listdict[liik]))
as iteration over dict alone is iterating over its keys, you are trying to sort keys of your dict - your itemgetter returns 'u' from 'sub....' and that is not too practical choice for sorting.

You need to sort values in your nested dicts, I think that this can work for you:
my_sorted = {key:sorted(values, key=lambda x:-x[1]) for key,values in listdict.items()}
And while i was reading your transformation of original nested dict to your dictlist, i didnt like hardcoded keys and combinations of keys, so i tried to rewrite it without fixed keys/combinations of keys. And i ended with this monstrosity, that should handle nested dicts and convert them to your kind of listdict.
from collections import defaultdict

def compress_dict(my_dict):
    """concatenates keys for nested dicts"""
    if isinstance(next(iter(my_dict.values())), dict):
        return {key+inkey:value for key in my_dict
                                for inkey,value in compress_dict(my_dict[key]).items()}
    else:
        return my_dict

def convert_dict(my_dict):
    listdict = defaultdict(list)
    cmp_dict = {key:compress_dict(obj) for key,obj in my_dict.items()}
    for key, obj in cmp_dict.items():
        for inkey, value in obj.items():
            listdict[inkey] += [[key, value]]
    return listdict
it seems that convert_dict(dict_to_sort) returns same dict as your  listdoc.
Reply
#4
Thanks a lot for your suggestions!

A version without lambda probably doesn't exist in Python 3, I fear?
lambda is too much magic for me, I prefer understanding what I am doing.

About the hardcoded keys, the names in the 'real' program aren''t just a concatenation. They combine a couple of 'hints' but it's not possible to construct them by the keys themself; the expressions would become too long for convenient human reading. The concatention was only a way to give a code fragment isolated from it's original environment.
However, as nobody else than me ever will take a view to this program, that should be a lesser problem ;-) . And the code may be handy in other situations (e.g. when doing experiment with several different parameters), so I'll try to keep it in mind. And maybe, if I learn more until that time, I'll be even able to understand all that strange constructs then. Actually, those 'for ... in...' are quite confusing for me. For the moment I would need to make a version that has at least ten times the lines but shows (me) what happens step for step...
Reply
#5
You can use operator.itemgetter in python3. Both
operator.itemgetter(1)
and
lambda x: x[1]
do exactly same thing - when applied on list or tuple, they return second element. lambda is probably more often used, its built-in and can be used without import.
Reply
#6
(Apr-01-2017, 08:17 PM)merlem Wrote: lambda is too much magic for me

Lambda is just an unnamed fuction, generally used for a temporary purpose. The syntax is lambda parameters: expression, which creates a function that returns the value of the expression. Note that you can't use a def statement in a function call, but you can use lambda in a function call.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#7
Quote:A version without lambda probably doesn't exist in Python 3, I fear?
We tried to explain this to you before here.
So no lambda,a regular function will still work.
>>> def sort_middle(tup):
...     return tup[1]
...     
>>> lst = [('Tom', 'C', 10), ('Kent', 'A', 12), ('Jenny', 'B', 15)]
>>> sorted(lst, key=sort_middle)
[('Kent', 'A', 12), ('Jenny', 'B', 15), ('Tom', 'C', 10)]
With lambda:
>>> lst = [('Tom', 'C', 10), ('Kent', 'A', 12), ('Jenny', 'B', 15)]
>>> sorted(lst, key=lambda tup: tup[1])
[('Kent', 'A', 12), ('Jenny', 'B', 15), ('Tom', 'C', 10)]
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  need to compare 2 values in a nested dictionary jss 2 847 Nov-30-2023, 03:17 PM
Last Post: Pedroski55
  Sorting numerical values provided by QAbstractTableModel BigMan 0 1,360 Jun-04-2022, 12:32 AM
Last Post: BigMan
  dict class override: how access parent values? Andrey 1 1,619 Mar-06-2022, 10:49 PM
Last Post: deanhystad
  Updating nested dict list keys tbaror 2 1,274 Feb-09-2022, 09:37 AM
Last Post: tbaror
  Removing nan values from a dict tomtom 8 7,012 Oct-05-2021, 06:44 PM
Last Post: tomtom
  changing key names in nested dict wardancer84 6 2,138 Sep-10-2021, 08:13 AM
Last Post: wardancer84
  sorting alphanumeric values in a human way idiotonboarding 3 2,611 Jan-22-2021, 05:57 PM
Last Post: idiotonboarding
Star Recursively convert nested dicts to dict subclass Alfalfa 1 2,880 Jan-22-2021, 05:43 AM
Last Post: buran
  Trouble with converting list , dict to int values! faryad13 7 3,731 Sep-04-2020, 06:25 AM
Last Post: faryad13
  Python 2 to 3 dict sorting joshuaprocious 2 57,251 May-14-2020, 03:28 PM
Last Post: joshuaprocious

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020