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具有最小值的两个键,即a
和c
。
最好的方法是什么?
(最终我想随机选择两者之一,但我认为这无关紧要)。
【问题讨论】:
你知道,因为 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:从字典中获取具有最小值但有多个最小值的键的主要内容,如果未能解决你的问题,请参考以下文章