【问题标题】:How to check if one of the following items is in a list?如何检查以下项目之一是否在列表中?
【发布时间】:2010-10-18 22:11:12
【问题描述】:

我正在尝试找到一种简短的方法来查看以下任何项目是否在列表中,但我的第一次尝试不起作用。除了编写一个函数来实现这一点之外,还有一种简单的方法来检查多个项目中的一个是否在列表中。

>>> a = [2,3,4]
>>> print (1 or 2) in a
False
>>> print (2 or 1) in a
True

【问题讨论】:

    标签: python


    【解决方案1】:

    啊,托拜厄斯,你打败了我。我在想your solution 的这种细微变化:

    >>> a = [1,2,3,4]
    >>> b = [2,7]
    >>> any(x in a for x in b)
    True
    

    【讨论】:

    • 我意识到这是一个非常古老的答案,但是如果一个列表很长而另一个很短,是否有一个可以产生更快性能的顺序? (即,x in long for x in shortx in short for x in long
    • @LukeSapan:你是对的。该顺序可以通过“print any(x in max(a,b,key=len) for x in min(a,b,key=len))”来获得。这将 x in long 用于 x in short。
    • 这是最好的答案,因为它使用生成器,一旦找到匹配项就会返回(正如其他人所说,只是不在这个答案上!)。
    • @Nuclearman,注意:如果ab 两个列表长度相同,max 和min 将返回最左边的列表,这使得any() 调用操作双方的名单相同。如果您绝对需要检查长度,请在第二次调用中颠倒列表的顺序:any(x in max(a, b, key=len) for x in (b, a, key=len))
    • @NoahBogart 您是正确的,该解决方案似乎与任何解决方案一样好。我还假设您的意思是:any(x in max(a, b, key=len) for x in min(b, a, key=len))(错过了分钟)。
    【解决方案2】:

    在 python 3 中,我们可以开始使用解包星号。给定两个列表:

    bool(len({*a} & {*b}))
    

    编辑:纳入 alkanen 的建议

    【讨论】:

    • @Anthony,它创建一个包含 a 中元素的集合,以及另一个包含 b 中元素的集合,然后它找到这些集合之间的交集(共享元素),如果存在则 any() 返回 true是任何真实的元素。如果唯一的共享元素是虚假的(例如数字 0),则该解决方案将不起作用。使用 len() 可能比使用 any() 更好
    • @alkanen 好电话
    • 为什么不用set函数?
    【解决方案3】:

    我不得不说,我的情况可能不是你想要的,但它可能会为你的想法提供另一种选择。

    我已经尝试了 set() 和 any() 方法,但速度仍然存在问题。所以我记得 Raymond Hettinger 说过,python 中的一切都是字典,只要有可能就使用 dict。所以这就是我尝试的。

    我使用带 int 的 defaultdict 来表示否定结果,并使用第一个列表中的项目作为第二个列表的键(转换为 defaultdict)。因为您可以使用 dict 即时查找,所以您可以立即知道该项目是否存在于 defaultdict 中。我知道您并不总是可以更改第二个列表的数据结构,但是如果您能够从一开始就更改,那么它会快得多。您可能必须将 list2(较大的列表)转换为 defaultdict,其中 key 是您要从小列表中检查的潜在值,值是 1(命中)或 0(未命中,默认值)。

    from collections import defaultdict
    already_indexed = defaultdict(int)
    
    def check_exist(small_list, default_list):
        for item in small_list:
            if default_list[item] == 1:
                return True
        return False
    
    if check_exist(small_list, already_indexed):
        continue
    else:
        for x in small_list:
            already_indexed[x] = 1
    

    【讨论】:

      【解决方案4】:

      我收集了其他答案和 cmets 中提到的几个解决方案,然后进行了速度测试。 not set(a).isdisjoint(b) 结果是最快的,结果是False 时也没有减慢多少。

      三个运行中的每一个都测试ab 的可能配置的小样本。时间以微秒为单位。

      Any with generator and max
              2.093 1.997 7.879
      Any with generator
              0.907 0.692 2.337
      Any with list
              1.294 1.452 2.137
      True in list
              1.219 1.348 2.148
      Set with &
              1.364 1.749 1.412
      Set intersection explcit set(b)
              1.424 1.787 1.517
      Set intersection implicit set(b)
              0.964 1.298 0.976
      Set isdisjoint explicit set(b)
              1.062 1.094 1.241
      Set isdisjoint implicit set(b)
              0.622 0.621 0.753
      

      import timeit
      
      def printtimes(t):
          print '{:.3f}'.format(t/10.0),
      
      setup1 = 'a = range(10); b = range(9,15)'
      setup2 = 'a = range(10); b = range(10)'
      setup3 = 'a = range(10); b = range(10,20)'
      
      print 'Any with generator and max\n\t',
      printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup1).timeit(10000000))
      printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup2).timeit(10000000))
      printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup3).timeit(10000000))
      print
      
      print 'Any with generator\n\t',
      printtimes(timeit.Timer('any(i in a for i in b)',setup=setup1).timeit(10000000))
      printtimes(timeit.Timer('any(i in a for i in b)',setup=setup2).timeit(10000000))
      printtimes(timeit.Timer('any(i in a for i in b)',setup=setup3).timeit(10000000))
      print
      
      print 'Any with list\n\t',
      printtimes(timeit.Timer('any([i in a for i in b])',setup=setup1).timeit(10000000))
      printtimes(timeit.Timer('any([i in a for i in b])',setup=setup2).timeit(10000000))
      printtimes(timeit.Timer('any([i in a for i in b])',setup=setup3).timeit(10000000))
      print
      
      print 'True in list\n\t',
      printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup1).timeit(10000000))
      printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup2).timeit(10000000))
      printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup3).timeit(10000000))
      print
      
      print 'Set with &\n\t',
      printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup1).timeit(10000000))
      printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup2).timeit(10000000))
      printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup3).timeit(10000000))
      print
      
      print 'Set intersection explcit set(b)\n\t',
      printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup1).timeit(10000000))
      printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup2).timeit(10000000))
      printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup3).timeit(10000000))
      print
      
      print 'Set intersection implicit set(b)\n\t',
      printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup1).timeit(10000000))
      printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup2).timeit(10000000))
      printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup3).timeit(10000000))
      print
      
      print 'Set isdisjoint explicit set(b)\n\t',
      printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup1).timeit(10000000))
      printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup2).timeit(10000000))
      printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup3).timeit(10000000))
      print
      
      print 'Set isdisjoint implicit set(b)\n\t',
      printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
      printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
      printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup3).timeit(10000000))
      print
      

      【讨论】:

        【解决方案5】:

        当您想到“检查 a 是否在 b 中”时,请考虑哈希(在本例中为集合)。最快的方法是对要检查的列表进行哈希处理,然后检查其中的每个项目。

        这就是 Joe Koberg 的回答很快的原因:检查集合交集非常快。

        当您没有大量数据时,制作集合可能会浪费时间。因此,您可以制作一组列表并检查每个项目:

        tocheck = [1,2] # items to check
        a = [2,3,4] # the list
        
        a = set(a) # convert to set (O(len(a)))
        print [i for i in tocheck if i in a] # check items (O(len(tocheck)))
        

        当您要检查的项目数量较少时,差异可以忽略不计。但是要对照一个大列表检查很多数字...

        测试:

        from timeit import timeit
        
        methods = ['''tocheck = [1,2] # items to check
        a = [2,3,4] # the list
        a = set(a) # convert to set (O(n))
        [i for i in tocheck if i in a] # check items (O(m))''',
        
        '''L1 = [2,3,4]
        L2 = [1,2]
        [i for i in L1 if i in L2]''',
        
        '''S1 = set([2,3,4])
        S2 = set([1,2])
        S1.intersection(S2)''',
        
        '''a = [1,2]
        b = [2,3,4]
        any(x in a for x in b)''']
        
        for method in methods:
            print timeit(method, number=10000)
        
        print
        
        methods = ['''tocheck = range(200,300) # items to check
        a = range(2, 10000) # the list
        a = set(a) # convert to set (O(n))
        [i for i in tocheck if i in a] # check items (O(m))''',
        
        '''L1 = range(2, 10000)
        L2 = range(200,300)
        [i for i in L1 if i in L2]''',
        
        '''S1 = set(range(2, 10000))
        S2 = set(range(200,300))
        S1.intersection(S2)''',
        
        '''a = range(200,300)
        b = range(2, 10000)
        any(x in a for x in b)''']
        
        for method in methods:
            print timeit(method, number=1000)
        

        速度:

        M1: 0.0170331001282 # make one set
        M2: 0.0164539813995 # list comprehension
        M3: 0.0286040306091 # set intersection
        M4: 0.0305438041687 # any
        
        M1: 0.49850320816 # make one set
        M2: 25.2735087872 # list comprehension
        M3: 0.466138124466 # set intersection
        M4: 0.668627977371 # any
        

        始终快速的方法是制作(列表中的)一组,但交集在大型数据集上效果最好!

        【讨论】:

          【解决方案6】:

          简单。

          _new_list = []
          for item in a:
              if item in b:
                  _new_list.append(item)
              else:
                  pass
          

          【讨论】:

          • 这没有回答问题。 OP 想知道 列表中的任何值 a 是否在列表 b 中。
          【解决方案7】:

          1 行没有列表推导。

          >>> any(map(lambda each: each in [2,3,4], [1,2]))
          True
          >>> any(map(lambda each: each in [2,3,4], [1,5]))
          False
          >>> any(map(lambda each: each in [2,3,4], [2,4]))
          True
          

          【讨论】:

            【解决方案8】:
            a = {2,3,4}
            if {1,2} & a:
                pass
            

            代码高尔夫版本。如果这样做有意义,请考虑使用集合。 我发现这比列表理解更具可读性。

            【讨论】:

            • 不错的一个,它肯定回答了这个问题,但它只适用于不可变的值。
            【解决方案9】:

            也许更懒一点:

            a = [1,2,3,4]
            b = [2,7]
            
            print any((True for x in a if x in b))
            

            【讨论】:

            • 和我发的差不多。
            • @BastienLéonard ...除了它更快,因为它使用生成器,因此any 可以提前返回,而您的版本必须在any 可以使用它之前从理解中构建整个列表。 @user89788 的回答稍微好一点,因为双括号是不必要的
            【解决方案10】:

            这将在一行中完成。

            >>> a=[2,3,4]
            >>> b=[1,2]
            >>> bool(sum(map(lambda x: x in b, a)))
            True
            

            【讨论】:

            • 我在这里没有得到 True >>> print a [2, 3, 4] >>> print b [2, 7] >>> reduce(lambda x, y: x in b, a) 错误
            • 是的。你说得对。 reduce() 并没有像我想象的那样处理布尔值。我上面写的修订版适用于这种情况。
            【解决方案11】:

            在某些情况下(例如唯一列表元素),可以使用集合操作。

            >>> a=[2,3,4]
            >>> set(a) - set([2,3]) != set(a)
            True
            >>> 
            

            或者,使用set.isdisjoint()

            >>> not set(a).isdisjoint(set([2,3]))
            True
            >>> not set(a).isdisjoint(set([5,6]))
            False
            >>> 
            

            【讨论】:

              【解决方案12】:

              我能想到的最好的:

              any([True for e in (1, 2) if e in a])
              

              【讨论】:

                【解决方案13】:

                想想代码实际上是怎么说的!

                >>> (1 or 2)
                1
                >>> (2 or 1)
                2
                

                这应该可以解释。 :) Python 显然实现了“惰性或”,这不足为奇。它执行如下操作:

                def or(x, y):
                    if x: return x
                    if y: return y
                    return False
                

                在第一个示例中,x == 1y == 2。在第二个例子中,反之亦然。这就是为什么它会根据它们的顺序返回不同的值。

                【讨论】:

                  【解决方案14】:
                  >>> L1 = [2,3,4]
                  >>> L2 = [1,2]
                  >>> [i for i in L1 if i in L2]
                  [2]
                  
                  
                  >>> S1 = set(L1)
                  >>> S2 = set(L2)
                  >>> S1.intersection(S2)
                  set([2])
                  

                  空列表和空集都是False,所以你可以直接将值作为真值。

                  【讨论】:

                  • 交叉点的想法给了我这个想法。 return len(set(a).intersection(set(b)))
                  • FWIW - 我做了一个速度比较,这里提供的第一个解决方案是迄今为止禁食。
                  • @user89788 使用生成器的答案再次快得多,因为any 可以在找到True 值后立即返回 - 它不必先构建整个列表跨度>
                  • 如果列表中有重复项,则第二个/集解决方案将不起作用(因为集仅包含每个项目之一)。如果 `L1 = [1,1,2,3]' 和 'L2 = [1,2,3]',所有项目都将被视为相交。
                  • 我知道这已经快 10 年了,但第一个解决方案似乎对我不起作用。我已将 L2 中的数字替换为字符串,但出现以下错误:TypeError: 'in ' requires string as left operand, not list
                  猜你喜欢
                  • 2011-04-25
                  • 2019-07-26
                  • 2022-08-24
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-02-25
                  • 1970-01-01
                  • 2011-09-02
                  • 2017-12-21
                  相关资源
                  最近更新 更多