NoThisIsPatrick
NoThisIsPatrick

Reputation: 153

Find Maximum Value in Nested Dictionary and return Key

So I have this block of code

dictionary = {
  'key1': {'a': 1, 'b': 2, 'c': 10}, 
  'key2': {'d': 1, 'e': 1, 'c': 11}, 
  'key3': {'d': 2, 'b': 1, 'g': 12}}

and

list1 = (a,b,c)

What I want to do is run a loop that finds the maximums of all the items in the list and returns the key. So for example, the maximum of 'c' would return 'key2', the maximum of 'b' would return 'key1', etc.

So far I have

for value in list1:
     m = max(dictionary, key=lambda v: dictionary[v][value])
     print(m + "\n")

But this only works if the same subkey exists in all keys in the dictionary. Any ideas on what to do?

Upvotes: 1

Views: 3180

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121924

Use float('-inf') when the key is missing:

m = max(dictionary, key=lambda v: dictionary[v].get(value, float('-inf')))

Negative infinity is guaranteed to be smaller than any existing value in the dictionaries, ensuring that nested dictionaries with the specific key missing are ignored.

Demo:

>>> dictionary = {
...   'key1': {'a': 1, 'b': 2, 'c': 10}, 
...   'key2': {'d': 1, 'e': 1, 'c': 11}, 
...   'key3': {'d': 2, 'b': 1, 'g': 12}}
>>> list1 = ('a', 'b', 'c')
>>> for value in list1:
...      print(value, max(dictionary, key=lambda v: dictionary[v].get(value, float('-inf'))))
... 
a key1
b key1
c key2

However, it'll be more efficient if you looped over all your dictionary values just once instead:

maximi = dict.fromkeys(list1, (None, float('-inf')))

for key, nested in dictionary.items():
    for k in nested.keys() & maximi:  # intersection of keys
        if maximi[k][0] is None or dictionary[maximi[k][0]][k] < nested[k]:
            maximi[k] = (key, nested[k])

for value in list1:
    print(value, maximi[value][0])

That's presuming you are using Python 3; in Python 2, replace .items() with .iteritems() and .keys() with .viewkeys().

Demo:

>>> maximi = dict.fromkeys(list1, (None, float('-inf')))
>>> for key, nested in dictionary.items():
...     for k in nested.keys() & maximi:  # intersection of keys
...         if maximi[k][0] is None or dictionary[maximi[k][0]][k] < nested[k]:
...             maximi[k] = (key, nested[k])
... 
>>> maximi
{'a': ('key1', 1), 'b': ('key1', 2), 'c': ('key2', 11)}
>>> for value in list1:
...     print(value, maximi[value][0])
... 
a key1
b key1
c key2

Upvotes: 8

Related Questions