1

My question arise from this discussion. I apologize, but I was not able to add a comment to ask my question under another answer because of my level. I have this list of tuples:

my_list = [('Scaffold100019', 98310), ('Scaffold100019', 14807), ('Scaffold100425', 197577), ('Scaffold100636', 326), ('Scaffold10064', 85415), ('Scaffold10064', 94518)]

I would like to make a dictionary which stores only the max value for each key defined as the first element of the tuple:

my_dict = {'Scaffold100019': 98310, 'Scaffold100425': 197577, 'Scaffold100636': 326, 'Scaffold10064': 94518}

Starting from the Marcus Müller's answer I have:

d = {}

#build a dictionary of lists
for x,y in my_list: d.setdefault(x,[]).append(y)

my_dict = {}

#build a dictionary with the max value only
for item in d: my_dict[item] = max(d[item])

In this way I reach my goal but, is there a sleeker way to complete this task?

Community
  • 1
  • 1
Revo
  • 87
  • 2
  • 10

3 Answers3

3

I suggest this solution with only one loop, quite readable:

my_dict = {}

for x,y in my_list:
    if x in my_dict.keys():
        my_dict [x] = max (y, my_dict [x])
    else:
        my_dict [x] = y
Laurent H.
  • 6,316
  • 1
  • 18
  • 40
2

You could use collections.defaultdict.

from collections import defaultdict

d = defaultdict(int)
for key, value in my_list:
    d[key] = max(d[key], value)

The above code works on your example data, but will only work in general if each key has a maximum value that is nonnegative. This is because defaultdict(int) returns zero when no value is set, so if all values for a given key are negative, the resulting max will incorrectly be zero.

If purely negative values are possible for a given key, you can make the following alteration:

d = defaultdict(lambda: -float('inf'))

With this alteration, negative infinity will be returned when a key isn't set, so negative values are no longer a concern.

root
  • 32,715
  • 6
  • 74
  • 87
0

Use the fact that everything is greater than None and the dictionaries get method with None as the fallback return value.

>>> d = {}
>>> for name, value in my_list:
...     if value > d.get(name, None):
...         d[name] = value
... 
>>> d
{'Scaffold100425': 197577, 'Scaffold10064': 94518, 'Scaffold100019': 98310, 'Scaffold100636': 326}

This will work for all values and hashes at most two times per loop.

timgeb
  • 76,762
  • 20
  • 123
  • 145