Python: получить ключ с наименьшим значением из словаря BUT несколько минимальных значений

Я пытаюсь сделать то же самое, что и Получить ключ, соответствующий минимальному значению в словаре, где мы хотим получить ключ, соответствующий минимальному значению в словаре.

Лучший способ:

min(d, key=d.get)

НО Я хочу применить это в словаре с несколькими минимальными значениями:

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

Обратите внимание, что ответ из вышеизложенного:

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

Однако мне нужны обе две клавиши с минимальным значением, а именно a и c.

Каким будет лучший подход?

(В конечном счете, я хочу выбрать одного из двух случайным образом, но я не думаю, что это имеет значение).

Ответы

Ответ 1

Один простой вариант - сначала определить минимальное значение, а затем выбрать все сопоставления клавиш для этого минимума:

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

Для Python 3 используйте d.values() вместо d.itervalues().

Для этого требуется два прохода через словарь, но он должен быть одним из самых быстрых способов сделать это.

Используя выборку коллектора, вы можете реализовать подход с одним проходом, который выбирает один из элементов случайным образом:

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

После записи этого кода я думаю, что этот вариант имеет довольно теоретический интерес...:)

Ответ 2

EDITED: теперь, используя setdefault, как предложено:)

Я не знаю, поможет ли это вам, но вы можете создать обратный словарь со значениями как ключ и ключи (в списке как значения).

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

Он напечатает это:

['a', 'c']

Однако, я думаю, что другие решения более компактны и, вероятно, более элегантны...

Ответ 3

min_keys = [k for k in d if all(d[m] >= d[k] for m in d)]

или, слегка оптимизированный

min_keys = [k for k, x in d.items() if not any(y < x for y in d.values())]

Это не так эффективно, как другие решения, но демонстрирует красоту питона (ну, по крайней мере, для меня).

Ответ 4

def get_rand_min(d):
    min_val = min(d.values())
    min_keys = filter(lambda k: d[k] == min_val, d)
    return random.choice(min_keys)

Ответ 5

Вы можете использовать heapq.nsmallest, чтобы получить N наименьших членов dict, а затем отфильтровать все, которые не равны самому низкому. Это при условии, что вы знаете максимальное количество наименьших членов, которые у вас есть, допустим здесь N. что-то вроде:

from heapq import nsmallest
from operator import itemgetter

#get the N smallest members
smallestN = nsmallest(N, myDict.iteritems(), itemgetter(1)))

#leave in only the ones with a score equal to the smallest one
smallest = [x for x in smallestN if x[1] == smallestN[0][1]]

Ответ 6

Это работает:

d = {'a' :1, 'b' : 2, 'c' : 1}
min_value = min(d.values())
result = [x[0] for x in d.items() if x[1] == k]

Пфф. После исправления кода для работы я получил ответ @Sven Marnach, поэтому не обращайте на это внимания:)

Ответ 7

minValue,minKey = min((v,k) for k,v in d.items())

Из-за вашей семантики вам нужно пройти через весь словарь хотя бы один раз. Это приведет к получению ровно 1 минимального элемента.

Если вам нужны все минимальные элементы в времени запроса O (log (N)), вы можете вставить свои элементы в очередь приоритетов по мере их создания (если можете). Очередь приоритета должна иметь O (1) время вставки и O (log (N)) time-min time. (Это будет так же плохо, как и сортировка, если все ваши элементы имеют одинаковое значение, но в противном случае может работать неплохо.)

Ответ 8

Вот еще один способ сделать это за один проход:

d = {'foo': 2, 'a' : 1, 'b' : 2, 'c' : 1, 'z': 99, 'x': 1}
current_min = d[d.keys()[0]]
min_keys = []
for k, v in d.iteritems():
    if v < current_min:
        current_min = v
        min_keys = [k]
    elif v == current_min:
        min_keys.append(k)
print min_keys
['a', 'x', 'c']

Ответ 9

Однопроходное решение:

 >>> result = [100000, []]
>>> for key, val in d.items():
...  if val < result[0]:
...   result[1] = [key]; result[0]=val;
...  elif val == result[0]:
...   result[1].append(key)
... 
>>> result
[1, ['a', 'c']]