【问题标题】:Python: get key with the least value from a dictionary BUT multiple minimum valuesPython:从字典中获取具有最小值但有多个最小值的键
【发布时间】: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:双引号之间未排序和随机的单词正是用于此目的。

标签: python dictionary multiple-instances minimum


【解决方案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()) 我已经更新了我的答案来解决这个问题。
            猜你喜欢
            • 2021-12-11
            • 1970-01-01
            • 2014-07-07
            • 2017-10-11
            • 1970-01-01
            • 2020-03-28
            • 2014-03-08
            • 2015-04-22
            • 1970-01-01
            相关资源
            最近更新 更多