Python:从字典中获取具有最小值但有多个最小值的键

Posted

技术标签:

【中文标题】Python:从字典中获取具有最小值但有多个最小值的键【英文标题】:Python: get key with the least value from a dictionary BUT multiple minimum values 【发布时间】:2012-04-14 06:08:39 【问题描述】:

我正在尝试做同样的事情 Get the key corresponding to the minimum value within a dictionary,这里我们要获取字典中最小值对应的键。

最好的办法似乎是:

min(d, key=d.get)

但是我想将此应用于具有多个最小值的字典:

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

请注意,上面的答案是:

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

但是,我需要both具有最小值的两个键,即ac

最好的方法是什么?

(最终我想随机选择两者之一,但我认为这无关紧要)。

【问题讨论】:

你知道,因为 dict 没有排序,你已经在这两者之间选择了一个“随机”的? @Rik Poggi,如果您将“随机”定义为“未指定排序”。 @DarenThomas:双引号之间未排序和随机的单词正是用于此目的。 【参考方案1】:

一个简单的选择是首先确定最小值,然后选择映射到该最小值的所有键:

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

对于 Python 3,请使用 d.values() 而不是 d.itervalues()

这需要两次遍历字典,但无论如何应该是最快的选择之一。

使用reservoir sampling,您可以实现随机选择其中一项的单通道方法:

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】:

已编辑:现在按照建议使用 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']

但是,我认为其他解决方案更紧凑,可能更优雅......

【讨论】:

你想要dict.setdefault,这样你就不必做单独的分配了。 谢谢,甚至不知道它存在 :)【参考方案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())]

它不像其他解决方案那样高效,但展示了 python 的美丽(至少对我而言)。

【讨论】:

当在 O(n) (Sven Marnach's) 中有一个简单的解决方案时,这确实在 O(n^2) 中运行。【参考方案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 个最小成员,然后过滤掉所有不等于最小的成员。前提是您知道可以拥有的最小成员的最大数量,假设这里是 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】:
minValue,minKey = min((v,k) for k,v in d.items())

由于您的语义,您需要至少浏览整个字典一次。这将准确检索 1 个最小元素。

如果您想要 O(log(N)) 查询时间内的所有最小项目,您可以在生成元素时将元素插入优先级队列(如果可以的话)。优先级队列必须有 O(1) 插入时间和 O(log(N)) 提取分钟时间。 (如果所有元素都具有相同的值,这将与排序一样糟糕,但否则可能会很好地工作。)

【讨论】:

【参考方案7】:

一次性解决方案是:

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

【讨论】:

100000 不可靠。 float("inf") 会。【参考方案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】:

这行得通:

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 的答案,所以,忽略这个;)

【讨论】:

哦,对了。我测试了第二个版本 (k = min(d.values()) 我已经更新了我的答案来解决这个问题。

以上是关于Python:从字典中获取具有最小值但有多个最小值的键的主要内容,如果未能解决你的问题,请参考以下文章

在包含“无”/“假”值的字典上获取具有最小值的键

Python从两个具有相同长度的列表中获取唯一值和最小值对

向 lambda 函数添​​加附加逻辑以从 python 字典中获取最小值

获取字典最小值的键,而该键在数组中

在列表中查找具有值的最小字典键的 Pythonic 方法?

列表字典中的Python最小值