【问题标题】:Finding key with minimum value in OrderedDict在 OrderedDict 中查找具有最小值的键
【发布时间】:2013-08-13 18:19:17
【问题描述】:

我需要在有序字典中找到其值最低的键,但只有当它在 my_list 中的位置为 True 时。

from collections import OrderedDict

my_list = [True,False,False,True,True,False,False,False,]

my_lookup = OrderedDict([('a', 2), ('b', 9), ('c', 4), ('d', 7),  
                         ('e', 3), ('f', 0), ('g', -5), ('h', 9)])

我知道如何使用 for 循环来做到这一点

mins=[]
i=0
for item in my_lookup.items():
    if my_list[i]:
        mins.append(item)
    i+=1
print min(mins,key=lambda x:x[1])[0]

打印

a

因为 a 在 my_list 中也是最低的。

这可行,但它很长,我想知道如何用理解或一行来做到这一点?

【问题讨论】:

    标签: python dictionary


    【解决方案1】:

    您可以使用itertools.compressmin 的键作为get 方法,

    >>> from itertools import compress
    >>> min(compress(my_lookup, my_list), key=my_lookup.get)
    a
    

    【讨论】:

    • +1,因为我相信这是使用标准 Python 工具的完美方式:该解决方案可以精确地完成工作,没有任何繁琐,并且以非常紧凑和易读的方式。
    【解决方案2】:

    还可以将生成器表达式和min结合起来:

    >>> min(((value, key) for ((key, value), flag) in zip(my_lookup.iteritems(), my_list) if flag))[1]
    'a'
    

    【讨论】:

    • 这真的不是最理想的:真的没有必要先找到选定的 pair 然后找到最小的 pair 只是为了以后只保留它的第一个元素。 Jared 的解决方案说明了原因。
    • @EOL 我不认为你是对的。 Python 3.x 中的 zip 返回迭代器(在 Python 2 中应使用 izip)。然后这个解决方案真的形成了元组,但是在 Python 中高效地实现了(元组在内部被重用)。 Jared 的解决方案使用字典查找,尽管具有O(1) 复杂性,但还是有一些开销。如果我在代码中看到compress,我将不得不搜索它的作用(因为compress 在Python 中不常用)。但是如果我看到这个带有生成器的解决方案,我会立刻明白它的作用。
    • @EOL 顺便说一句,你是对的。我的解决方案结果慢了 2 倍。请参阅:ideone.com/L2cnke 但它与使用compressed 无关(因为f3f1 一样有效)。但事实证明,打包成元组然后解包比进行字典查找要慢(即使元组在 CPython 中被重用)。
    • @EOL 顺便说一句,这是一个非常有趣的性能问题。我asked here 更好地理解它。
    • 感谢您对速度问题的跟进。请注意,我从未打算评论您的答案的执行速度,而只是评论其编程风格。总而言之,我的意思是 Python 提供了一种比 Decorate-Sort-Undecorate 模式更简单的方法,因为它允许绕过显式装饰然后取消装饰操作。因此,min(…, key=…) 需要更少的认知步骤来理解,因此更快地理解(即更清晰)。无论如何,执行速度讨论很有趣,谢谢。 :)
    【解决方案3】:

    双线:

    from itertools import izip
    print min((lookup_key for (lookup_key, keep) in izip(my_lookup.iterkeys(),
                my_list) if keep), key=my_lookup.get)
    

    【讨论】:

    • 这是对现有标准itertools.compress() 的重新实现。我完全支持 Python 程序员使用 Python 提供的高效和标准工具,而不是用需要更长时间阅读和理解的表达式重新发明轮子……
    • @EOL:点了,我同意——完全忘记了itertools.compress(),它是在 2.7/3.1 中添加到模块中的......所以也许这对仍在使用早期版本的人有用。
    • 好点。我重写了您的解决方案以使其更易读(“keep”比item[0] 具有更明显的含义,并且我避免使用iteritems() 并将item 命名为not 其中一项)。
    • @EOL:同样,好点,所以你的编辑很好,除了我还认为避免长行提高可读性,尤其是在 SO 的代码框中。
    • 好的。由于只需要密钥,我将iteritems 替换为iterkeys,这样就不需要item[0]
    【解决方案4】:

    对于它的价值,原始代码的轻微变化可以合理地执行(与 ovgolovin 的方法相当)并且可读性很好:

    minimum = (None, float('inf'))
    for i, item in enumerate(my_lookup.items()):
        if not my_list[i]:
            continue
        if item[1] < minimum[1]:
            minimum = item
    return minimum[0]
    

    根据 ovgolovin 的 ideone 基准,即使是原始代码也只比这慢一点。当然,Jared 的解决方案速度更快,时间也更短。

    【讨论】:

    • 我真的不建议任何人使用它:阅读和理解它比 Jared 的简单解决方案要长得多。 Python 的优点之一是它允许人们不必像在 C 中那样编程。:)
    • @EOL,我同意,Jared 的解决方案非常优雅。我的观点是,正如用户要求的那样,较短的代码或单行代码不一定是要争取的。它们应该是手段而不是目的。
    • 是的,几行代码确实比一行代码更好。目标确实应该是代码的易读性(理解速度)。单行文字的问题在于有两种单行文字:一种是为了尽可能少的字符做很多事情,即使这会牺牲易读性,另一种是实际上非常易读,因为它们使用了高级,强大但标准的工具。 (Jared 的非常好的解决方案可以说属于第二类。)
    猜你喜欢
    • 2019-02-08
    • 2021-10-17
    • 1970-01-01
    • 2016-09-10
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    相关资源
    最近更新 更多