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']]