Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: get key with the least value from a dictionary BUT multiple minimum values

I'm trying to do the same as Get the key corresponding to the minimum value within a dictionary, where we want to get the key corresponding to the minimum value in a dictionary.

The best way appears to be:

min(d, key=d.get)

BUT I want to apply this on a dictionary with multiple minimum values:

d = {'a' : 1, 'b' : 2, 'c' : 1}

Note that the answer from the above would be:

>>> min(d, key=d.get)
'a'

However, I need both the two keys that have a minimum value, namely a and c.

What would be the best approach?

(Ultimately I want to pick one of the two at random, but I don't think this is relevant).

like image 368
gozzilli Avatar asked Mar 30 '12 14:03

gozzilli


People also ask

How do you get the key of the minimum value in a dictionary Python?

To find the minimum value in a Python dictionary you can use the min() built-in function applied to the result of the dictionary values() method.

Can Python dictionary keys have multiple values?

In python, if we want a dictionary in which one key has multiple values, then we need to associate an object with each key as value. This value object should be capable of having various values inside it. We can either use a tuple or a list as a value in the dictionary to associate multiple values with a key.

How do you find the maximum and minimum of a dictionary?

In Python to find the minimum and maximum values in a dictionary, we can use the built-in min() and max() functions. In Python the max() function is used to find the maximum values in a given dictionary. While in the case of min() function is used to find the minimum values in a dictionary.


2 Answers

One simple option is to first determine the minimum value, and then select all keys mapping to that minimum:

min_value = min(d.itervalues())
min_keys = [k for k in d if d[k] == min_value]

For Python 3 use d.values() instead of d.itervalues().

This needs two passes through the dictionary, but should be one of the fastest options to do this anyway.

Using reservoir sampling, you can implement a single pass approach that selects one of the items at random:

it = d.iteritems()
min_key, min_value = next(it)
num_mins = 1
for k, v in it:
    if v < min_value:
        num_mins = 1
        min_key, min_value = k, v
    elif v == min_value:
        num_mins += 1
        if random.randrange(num_mins) == 0:
            min_key = k

After writing down this code, I think this option is of rather theoretical interest… :)

like image 133
Sven Marnach Avatar answered Sep 20 '22 05:09

Sven Marnach


EDITED: Now using setdefault as suggested :)

I don't know if that helps you but you could build a reverse dictionary with the values as key and the keys (in a list as values).

d = {'a' : 1, 'b' : 2, 'c' : 1}
d2 = {}
for k, v in d.iteritems():
    d2.setdefault(v, []).append(k)
print d2[min(d2)]

It will print this:

['a', 'c']

However, I think the other solutions are more compact and probably more elegant...

like image 45
katzenversteher Avatar answered Sep 19 '22 05:09

katzenversteher