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 passsomedict.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']))