Home > database >  How to sort a dict of dicts by the length of a list inside child dicts
How to sort a dict of dicts by the length of a list inside child dicts

Time:10-27

I'm a beginner to Python, and for the sake of learning I looked up some challenges to solve. Here I have a dictionary, containing several dictionaries, each having a list of dicts. My job here is to sort the dictionary, in descending order, based on which child of somedict has more elements in the key list.

somedict = {
    'a': {
        'key' : [{}, {}, ]
    },
    'b': {
        'key' : [{}, ]
    },
    'c': {
        'key' : [{}, {}, {} ]
    },
    'd': {
        'key' : [{}, {}, {}, ]
    },
    'e': {
        'key' : [{}, {}, {} ]
    },
    'f': {
        'key' : [{}, ]
    },
    'g': {
        'key' : [{}, {} ]
    },
    'h': {
        'key' : [{}, {}, {},]
    }

}

sorted_dict = sorted(somedict, key= lambda k: len(k['a']['key']))

print(sorted_dict)

While trying to use sorted(), I get:

TypeError: string indices must be integers

CodePudding user response:

What you need to do is to sort the keys as a list, and from that sorted list rebuild the dict:

somedict = {
    ...
    # contents elided
}
keys = list(somedict.keys())
sorted_keys = sorted(keys, key= lambda k: len(somedict[k]['key']), reverse=True)

print(sorted_keys)

sorted_dict = {k:somedict[k] for k in sorted_keys}

print(sorted_dict)

Output

['c', 'd', 'e', 'h', 'a', 'g', 'b', 'f']
{'c': {'key': [{}, {}, {}]}, 'd': {'key': [{}, {}, {}]}, 'e': {'key': [{}, {}, {}]}, 'h': {'key': [{}, {}, {}]}, 'a': {'key': [{}, {}]}, 'g': {'key': [{}, {}]}, 'b': {'key': [{}]}, 'f': {'key': [{}]}}

And this can be shortened to one line:

sorted_dict = {k:somedict[k] for k in sorted(somedict, key=lambda k: len(somedict[k]['key']), reverse=True)}

CodePudding user response:

The problem is the lambda you are passing for key and since you want to sort it in descending order, you need also to add reverse=True.

sorted_keys = sorted(somedict, key=lambda k: len(somedict[k]['key']), reverse=True)
print(sorted_keys)

# then you can build the sorted dictionary
sorted_dict = {k:somedict[k] for k in sorted_keys}
print(sorted_dict)

Output

['c', 'd', 'e', 'h', 'a', 'g', 'b', 'f']

CodePudding user response:

Yes, here you go:

somedict = {
    'a': {
        'key' : [{}, {}, ]
    },
    'b': {
        'key' : [{}, ]
    },
    'c': {
        'key' : [{}, {}, {} ]
    },
    'd': {
        'key' : [{}, {}, {}, ]
    },
    'e': {
        'key' : [{}, {}, {} ]
    },
    'f': {
        'key' : [{}, ]
    },
    'g': {
        'key' : [{}, {} ]
    },
    'h': {
        'key' : [{}, {}, {},]
    }

}

sorted_dict = sorted(somedict, key=lambda k: len(somedict[k]["key"]))

print(sorted_dict)

Comparing to your attempt

Basically, sorted iterates over the incoming iterable (here a dict) and the custom key parameter gives you the key of the dictionary for each element of that dictionary. Here, the key is called k as a variable name, so the question is:

"Given the key of the dictionary, how do we get the length of the underlying list?"

In this case, we do that by calling somedict[k] first, and then the key string. This returns the array. We then simply call len(...) on that to get the list length.

For example, for the first element in the dict the key is a, so somedict["a"] returns the subdict: {'key' : [{}, {}, ]}. In this subdict, we then extract the value of the key called, also, key - with: somedict["a"]["key"] and get [{}, {}, ]. Then we take the length with len([{}, {}, ]) which is 2.

Hope that helps!

CodePudding user response:

You almost got it right. Two edits:

  • sorted needs the keys and the values of the top-level dict. So you need to pass somedict.items(). This passes a list of tuples with key, value pairs.
  • in the sorting lambda, you the the key, value tuple as parameter. You are interested in the value (2nd tuple item = index 1) and then the ‘key’ of it.

So I think this does the trick:

sorted_dict = sorted(somedict.items(), key=lambda kv: len(kv[1]['key']))
  • Related