如何检查一个列表中是否包含所有以下项目?

179

我发现有一个相关的问题,关于如何查找列表中是否存在至少一个项目:
如何检查以下项之一是否在列表中?

但是,查找所有项目是否都存在于列表中的最佳和Pythonic方法是什么?

在搜索文档时,我找到了这个解决方案:

>>> l = ['a', 'b', 'c']
>>> set(['a', 'b']) <= set(l)
True
>>> set(['a', 'x']) <= set(l)
False

另一种解决方案是这样的:

>>> l = ['a', 'b', 'c']
>>> all(x in l for x in ['a', 'b'])
True
>>> all(x in l for x in ['a', 'x'])
False

但在这里你需要打更多的字。

还有其他解决方案吗?


6
set(smaller) <= set(larger) 有什么问题? - eumiro
1
我认为你的第二个解决方案使用'all'看起来很好,符合Pythonic风格。 - Jiho Noh
Python:查看一个集合是否完全包含另一个集合?- Stack Overflow 相同的问题,只是涉及到列表/集合的区别。 - user202729
8个回答

284

在Python中,诸如 <= 这样的运算符通常不会被重载为意义明显不同于“小于或等于”的操作符。标准库很少这样做 - 这让我感觉像是遗留API。

使用等效且更易于理解的方法 set.issubset。请注意,您不需要将参数转换为集合;如果需要,它会自动为您转换。

set(['a', 'b']).issubset(['a', 'b', 'c'])

5
不知道你可以直接将列表作为参数传递给issubset...好! - tsimbalar
4
虽然我同意这种情绪,但我对“<=”和“issubset”意味着相同的事情感到非常满意。你为什么不喜欢它? - Kirk Strauser
8
主要是因为对于一个集合而言,不明显 <= 是什么意思,除非查看文档或者已经知道在集合论中它的含义,而每个人都可以自动地理解 issubset 的含义。 - Glenn Maynard
6
你知道表示(非真)子集的数学符号吗?它看起来很像一个圆形的 <= ;) - dom0
喜欢这个解决方案。有没有办法获取索引位置或列表值,而不是布尔值(True:False)? - Vlad Gulin
非严格子集数学运算符是(部分)排序关系(在有意义的上下文中)。因此,将其表示为<=是有意义的。 - Nephanth

73

我可能会按照以下方式使用set

set(l).issuperset(set(['a','b'])) 

或者说反过来:

set(['a','b']).issubset(set(l)) 

我认为这种写法更易读,但可能有些过度。在计算集合的并/交/差时,集合特别有用,但在这种情况下可能不是最佳选择...


实际上,MySet.issubset(MyOtherSet)MySet <= MyOtherSet 是一样的。 - Wok
1
@wok:哦,我不知道那个,但是我认为“<=”语法有点混淆,因为类似的语法可以用于列表,但意义却截然不同。 - tsimbalar
3
如果你回忆一下,包含关系在任何一组集合上定义了一个偏序关系,那么这并不是真的很难理解。但对于序列来说,“<=”有它所代表的含义还是会让人略感困惑:人们可能预期它表示“是子序列”的意思,而不是词典序。 - aaronasterling
1
@aaronasterling:嗯,就我个人而言,在编写代码时我不会过多考虑“偏序”,但我同意使用<=与序列也感觉有些奇怪... - tsimbalar
比较运算符只定义了一个偏序,无论你是否知道它的名称 :),这是相当不寻常的。我认为大多数人直觉地期望 !(a <= b) 意味着 b <= a,但是偏序并不是这样的——set([1]) <= set([2])set([2]) <= set([1]) 都是错误的。 - Glenn Maynard
6
我在这里遇到了一个小问题,我想提一下:如果您使用这种方法,您正在将您的列表转换为集合(set),这意味着没有重复的元素。 set(['a','a']).issubset(['a']) 返回 True - Orangestar

23

我喜欢这两个,因为它们看起来最合乎逻辑,后者更短,可能是最快的(在这里使用了set文字语法,该语法已经被移植到 Python 2.7):

all(x in {'a', 'b', 'c'} for x in ['a', 'b'])
#   or
{'a', 'b'}.issubset({'a', 'b', 'c'})

“all”解决方案在使用timeit()进行测量时是最快的。这应该被接受的答案。 - Attersson

12

如果您的列表包含像这样的重复项:

v1 = ['s', 'h', 'e', 'e', 'p']
v2 = ['s', 's', 'h']

Sets不包含重复元素。因此,以下代码返回True。

set(v2).issubset(v1)

为了计算重复项,您可以使用以下代码:

v1 = sorted(v1)
v2 = sorted(v2)


def is_subseq(v2, v1):
    """Check whether v2 is a subsequence of v1."""
    it = iter(v1)
    return all(c in it for c in v2) 

因此,以下行会返回False。

is_subseq(v2, v1)

2

这不是 OP 的情况,但是 - 对于任何希望在 字典 中断言交集的人,由于搜索不当(例如我),导致来到这里 - 你需要使用 dict.items 进行操作:

>>> a = {'key': 'value'}
>>> b = {'key': 'value', 'extra_key': 'extra_value'}
>>> all(item in a.items() for item in b.items())
True
>>> all(item in b.items() for item in a.items())
False

这是因为dict.items返回键/值对的元组,就像Python中的任何对象一样,它们是可以相互比较的。


2
另一个解决方案是:
l = ['a', 'b', 'c']
potential_subset1 = ['a', 'b']
potential_subset2 = ['a', 'x']
print(False not in [i in l for i in potential_subset1]) # True
print(False not in [i in l for i in potential_subset2]) # False

我的解决方案之所以很棒,是因为你可以通过将列表放在一行内来编写单行代码。

1
使用lambda表达式实现这个例子的方法如下:
issublist = lambda x, y: 0 in [_ in x for _ in y]

3
请在回答中添加评论以解释/阐述您的答案。 - Sharad
2
请注意,在这种情况下使用“_”作为变量名是令人困惑的。这是因为按照惯例,“_”用于表示您不使用其值的变量(“丢弃变量”)。请参见:https://dev59.com/AW025IYBdhLWcg3wpHh-#5893946 - Nephanth
@Nephanth 三年后...谢谢,现在我知道了。 - Jundullah

0

简洁语法

在 Python 解释器上实验时,我发现了一种非常易读的语法。

>>> my_list = [1, 2, 3, 4, 5]
>>> (6 or 7) in my_list
False
>>> (2 or 6) in my_list
True
>>> (2 and 6) in my_list
False
>>> (2 and 5) in my_list
True

搜索项列表

如果您有一个长的对象列表需要搜索,保存在sub_list变量中:

>>> my_list = [1, 2, 3, 4, 5]
>>> sub_list = ['x', 'y']

如果超集合中包含任何(至少一个)项(使用“或”语句):
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
False

>>> sub_list[0] = 3
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True

如果所有项目都包含在超集中(使用and语句),那么sub_list是完全子集。还涉及一点德摩根定律
>>> next((False for item in sub_list if item not in my_list), True)
False

>>> sub_list[1] = 2
>>> next((False for item in sub_list if item not in my_list), True)
True
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True

2
顶部的语法“看起来不错”,但它是误导性的。实际上,它在in语句中只使用一个数字。因此,(2或6)在我的列表中True,因为(2或6)2,但(6或2)在我的列表中False,因为(6或2)6 - Michael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接