【问题标题】:check equality against a collection of values根据一组值检查相等性
【发布时间】:2018-08-03 07:55:06
【问题描述】:

假设我想检查一个变量是否等于几个值之一。我应该使用以下哪种表达方式?

if s == 'one' or s == 'two' or s == 'three':
    pass

if s in ('one', 'two', 'three'):
    pass

if s in ['one', 'two', 'three']:
    pass

if s in {'one', 'two', 'three'}:
    pass

编辑:从答案/cmets,我了解到:

  • 最不推荐第一个变体,其他变体被视为同样“pythonic”。
  • 对于短序列,检查成员资格的性能差异可以忽略不计。元组的创建成本最低,集合需要计算哈希。
  • 这四种变体在某些极端情况下并不等价:
    • in 运算符检查身份和相等性。
    • 逻辑or 短路。我怀疑元组和列表的成员资格测试应该按顺序评估,因此也应该短路。
    • 集合需要可散列的元素。

【问题讨论】:

  • 我通常使用集合,因为复杂度为 O(1)。
  • 如果可以重复使用该套装,理论上最后一个更快,但对于仅三个项目没有实质性差异。
  • 请注意,它们并非严格相等 == 检查相等,但 in 运算符检查相等或身份
  • @NicolasMalebranche 是的,请参阅stackoverflow.com/a/48867273/6260170

标签: python equality


【解决方案1】:

如果您要重复多次或必须处理许多替代方案,您应该使用set

但是,如果只使用一次,建议使用tuples

在任何情况下都不推荐第一种。

【讨论】:

    【解决方案2】:

    我认为以下三个是最好的:

    if s in ('one', 'two', 'three'):
        pass
    
    if s in ['one', 'two', 'three']:
        pass
    
    if s in {'one', 'two', 'three'}:
        pass
    

    但也许仍然:

    if s in {'one', 'two', 'three'}:
        pass
    

    还是最好的

    时间

    %timeit if 'one' in ('one', 'two', 'three'):pass
    

    输出:

    The slowest run took 21.60 times longer than the fastest. This could mean 
    that an intermediate result is being cached.
    10000000 loops, best of 3: 63.4 ns per loop
    

    &

    %timeit if 'one' in ['one', 'two', 'three']:pass
    

    输出:

     10000000 loops, best of 3: 50.7 ns per loop
    

    &

    %timeit if 'one' in {'one', 'two', 'three'}:pass
    

    输出:

    10000000 loops, best of 3: 50.3 ns per loop
    

    最后我更喜欢set({}) 因为它是最快的

    元组是我最不喜欢的最慢的(在元组、列表和集合中)

    【讨论】:

    • 你真的应该说为什么你认为这些是最好的
    • 好!不过,我认为您无法从这些时间中得出明确的结论
    • 我得到了不同的结果。集合占用了列表和元组大约 20% 的时间,它们都非常相似。测试是在 52 个字符的集合中找到一个字符,这显然比提问者要寻找的要多得多,但可能是更适用于列表和元组的集合效率的测试。
    【解决方案3】:

    要检查三个值,没关系。

    第一个if s == 'one' or s == 'two' or s == 'three': 可以说是不那么pythonic。在其中一个值比另一个值更有可能的情况下,它可能会很方便。在这种情况下,您可以通过将最可能的值放在前面来利用惰性求值,从而避免在大多数情况下对整个表达式求值。

    使用集合 if s in {'one', 'two', 'three'}: 需要预先创建集合 O(n) 散列的成本,但在有许多变量要检查、多次检查或集合包含许多重复项的情况下会产生很大的好处。

    另外两个基本相同。与列表相比,我更倾向于不可变的元组,但这与问题没有直接关系。

    对 3 个值的情况下的性能差异进行计时是没有用的。

    【讨论】:

    • 当你可以使用if 'one' in ('one', 'two', 'three') 时,我很难推荐循环示例,如问题所示。
    • 我同意,我删除了它,因为它确实是多余的
    【解决方案4】:

    您可以使用您提出的任何选项,但第一个选项可能不太方便使用。

    使用set 的最后一个选项在性能方面应该是最有效的,但这实际上取决于您的收藏时间。

    如果您的收藏中没有数千个条目,只需使用一个列表,它对于任何用途都更常见且更灵活。

    【讨论】:

      猜你喜欢
      • 2022-01-07
      • 1970-01-01
      • 2021-05-06
      • 1970-01-01
      相关资源
      最近更新 更多