Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何测试列表中多个值的成员资格?_Python - Fatal编程技术网

Python 如何测试列表中多个值的成员资格?

Python 如何测试列表中多个值的成员资格?,python,Python,我想测试两个或多个值是否在列表中具有成员资格,但我得到了一个意外的结果: >>> 'a','b' in ['b', 'a', 'foo', 'bar'] ('a', True) 那么,Python可以同时测试列表中多个值的成员身份吗? 这个结果意味着什么?这是您想要的,并且几乎在所有情况下都有效: >>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b']) True ['b','a','foo','

我想测试两个或多个值是否在列表中具有成员资格,但我得到了一个意外的结果:

>>> 'a','b' in ['b', 'a', 'foo', 'bar']
('a', True)
那么,Python可以同时测试列表中多个值的成员身份吗?
这个结果意味着什么?

这是您想要的,并且几乎在所有情况下都有效:

>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
True
['b','a','foo','bar']中的表达式
'a','b'无法正常工作,因为Python将其解释为元组:

>>> 'a', 'b'
('a', 'b')
>>> 'a', 5 + 2
('a', 7)
>>> 'a', 'x' in 'xerxes'
('a', True)
其他选择 还有其他方法可以执行此测试,但它们不能用于许多不同类型的输入。正如所指出的,您可以使用集合来解决这个问题

>>> set(['a', 'b']).issubset(set(['a', 'b', 'foo', 'bar']))
True
>>> {'a', 'b'} <= {'a', 'b', 'foo', 'bar'}
True
速度测试 在许多情况下,子集测试将比
all
更快,但差异并不令人震惊——除非问题与此无关,因为集合不是选项。将列表转换为集合只是为了进行这样的测试并不总是值得费心的。而将发电机转换成发电机组有时可能会造成难以置信的浪费,从而使程序速度降低许多数量级

下面是一些用于说明的基准。最大的区别在于
容器
项目
都相对较小。在这种情况下,子集方法大约快一个数量级:

>>> smallset = set(range(10))
>>> smallsubset = set(range(5))
>>> %timeit smallset >= smallsubset
110 ns ± 0.702 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
>>> %timeit all(x in smallset for x in smallsubset)
951 ns ± 11.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
这看起来有很大的不同。但是只要
容器
是一个集合,
所有
仍然可以在更大的范围内完美地使用:

>>> bigset = set(range(100000))
>>> bigsubset = set(range(50000))
>>> %timeit bigset >= bigsubset
1.14 ms ± 13.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit all(x in bigset for x in bigsubset)
5.96 ms ± 37 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
使用子集测试的速度更快,但在这种规模下只有大约5倍。速度的提高是由于Python支持的
set
的快速
c
实现,但基本算法在这两种情况下是相同的

如果由于其他原因,
已存储在列表中,则在使用子集测试方法之前,必须将它们转换为集合。然后加速比下降到2.5倍左右:

>>> %timeit bigset >= set(bigsubseq)
2.1 ms ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
如果您的
容器是一个序列,需要先进行转换,则加速比甚至更小:

>>> %timeit set(bigseq) >= set(bigsubseq)
4.36 ms ± 31.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
我们唯一一次得到灾难性的缓慢结果是当我们按顺序离开
容器时:

>>> %timeit all(x in bigseq for x in bigsubseq)
184 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
当然,我们只有在必要的时候才会这么做。如果
bigseq
中的所有项都是可散列的,那么我们将改为:

>>> %timeit bigset = set(bigseq); all(x in bigset for x in bigsubseq)
7.24 ms ± 78 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
这只比备选方案快1.66倍(
set(bigseq)>=set(bigseq)
,时间在4.36以上)

所以子集测试通常更快,但不会有令人难以置信的优势。另一方面,让我们看看什么时候
all
更快。如果
的长度为1000万个值,并且可能具有不在
容器中的值,该怎么办

>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); set(bigset) >= set(hugeiter)
13.1 s ± 167 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); all(x in bigset for x in hugeiter)
2.33 ms ± 65.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
在这种情况下,将发电机转换成发电机组是非常浪费的。
集合
构造函数必须消耗整个生成器。但是
all
的短路行为确保只需要消耗发电机的一小部分,因此它比子集测试快四个数量级

诚然,这是一个极端的例子。但正如它所显示的,你不能假设一种方法或另一种方法在所有情况下都会更快

其结果 大多数情况下,将
容器
转换为一个集合是值得的,至少如果它的所有元素都是可散列的。这是因为集合中的
是O(1),而序列中的
是O(n)


另一方面,有时使用子集测试可能只是值得的。如果您的测试项目已经存储在一个集合中,那么一定要这样做。否则,
all
只会稍微慢一点,并且不需要任何额外的存储。它也可以用于大型项目生成器,有时在这种情况下会提供巨大的加速。

我很确定
中的
具有更高的优先级,
因此您的语句被解释为
'a',(['b'…]中的'b')
,然后计算为
'a',由于
'b'
在数组中,因此为True


请参阅前面的答案,了解如何执行所需操作。

Python解析器将该语句作为元组进行计算,其中第一个值是
'a'
,第二个值是['b','a','foo','bar']
中的表达式
'b'。(计算结果为
True

您可以编写一个简单的函数来执行您想要的操作,不过:

def all_in(candidates, sequence):
    for element in candidates:
        if element not in sequence:
            return False
    return True
把它叫做:

>>> all_in(('a', 'b'), ['b', 'a', 'foo', 'bar'])
True
另一种方法是:

>>> set(['a','b']).issubset( ['b','a','foo','bar'] )
True

这里给出的两个答案都不会处理重复的元素。例如,如果正在测试[1,2,2]是否为[1,2,3,4]的子列表,则两者都将返回True。这可能是你的意思,但我只是想澄清一下。
如果要为[1,2,3,4]中的[1,2,2]返回false,则需要对两个列表进行排序,并在每个列表上使用移动索引检查每个项目。只是一个稍微复杂一点的for循环。

没有lambdas,你怎么能成为pythonic。。不要当真。。但这种方法也有效:

orig_array = [ ..... ]
test_array = [ ... ]

filter(lambda x:x in test_array, orig_array) == test_array
如果要测试数组中是否有任何值,请省略结尾部分:

filter(lambda x:x in test_array, orig_array)

我想说,我们甚至可以不使用方括号

array = ['b', 'a', 'foo', 'bar']
all([i in array for i in 'a', 'b'])
我认为这比选择的答案更好的原因是,您确实不需要调用'all()'函数。在IF语句中,空列表的计算结果为False,非空列表的计算结果为True

if [x for x in ['a','b'] if x in ['b', 'a', 'foo', 'bar']]:
    ...Do something...
例如:

>>> [x for x in ['a','b'] if x in ['b', 'a', 'foo', 'bar']]
['a', 'b']
>>> [x for x in ['G','F'] if x in ['b', 'a', 'foo', 'bar']]
[]

如果要检查所有输入匹配项

>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
>>> any(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
如果要检查至少一个匹配项

>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
>>> any(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
我是这样做的:

A=['A','b','c']
B=['c']
逻辑=[(B中的x)表示A中的x]
如果逻辑为真:
做点什么

Fun fact:
set(['a',b'])从Python2.7开始,您可以使用
{'a',b'}'两者吗?答案不止两个。你的意思是所有答案都会遇到这个问题,还是只有两个答案(如果是的话,是哪一个答案)?只是提醒一下,在Python3中,
filter
是一个生成器,这不会像预期的那样起作用。如果你想得到一个结果,你需要把它包装在
列表中
>>> any(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])