如何检查一个列表中的所有项是否都在另一个列表中?
我有两个列表,比如说:
List1 = ['a','c','c']
List2 = ['x','b','a','x','c','y','c']
现在我想检查一下,列表1中的所有元素是否都在列表2中。在这个例子里,所有元素确实都在。我不能用子集函数,因为列表里可能有重复的元素。我可以用一个循环来计算列表1中每个项目出现的次数,然后看看这个次数是否小于或等于列表2中对应项目的次数。有没有更好的方法来做到这一点呢?
谢谢。
6 个回答
1
这里有一个使用Counter和内置的交集方法的解决方案(注意,-
是多重集合的差集,而不是逐个元素的减法):
from collections import Counter
def is_subset(l1, l2):
c1, c2 = Counter(l1), Counter(l2)
return not c1 - c2
测试:
>>> List1 = ['a','c','c']
>>> List2 = ['x','b','a','x','c','y','c']
>>> is_subset(List1, List2)
True
7
请注意以下几点:
>>>listA = ['a', 'a', 'b','b','b','c']
>>>listB = ['b', 'a','a','b','c','d']
>>>all(item in listB for item in listA)
True
如果你像读英语那样理解“all”这一行,这并没有错,但可能会让人误解,因为listA有第三个'b',而listB没有。
这个问题也一样:
def list1InList2(list1, list2):
for item in list1:
if item not in list2:
return False
return True
只是提醒一下,下面这个是行不通的:
>>>tupA = (1,2,3,4,5,6,7,8,9)
>>>tupB = (1,2,3,4,5,6,6,7,8,9)
>>>set(tupA) < set(TupB)
False
如果你把元组转换成列表,还是不行。我不知道为什么字符串可以用,但整数不行。
这个方法可以用,但同样存在不记录元素出现次数的问题:
>>>set(tupA).issubset(set(tupB))
True
使用集合并不是解决多次出现元素匹配的全面方案。
不过,这里有一个一行代码的解决方案,改编自shantanoo的回答,不需要try/except:
all(True if sequenceA.count(item) <= sequenceB.count(item) else False for item in sequenceA)
这是一个内置函数,结合了列表推导式和三元条件运算符。Python真是太棒了!注意“<=”不应该写成“==”。
使用这个方案,序列A和B可以是元组、列表以及其他有“count”方法的“序列”。这两个序列中的元素可以是大多数类型。我现在不建议用这个方法处理字典,所以才用“序列”而不是“可迭代对象”。
51
当你不在乎某个元素出现的次数时,你仍然可以使用子集的功能,只需动态创建一个集合:
>>> list1 = ['a', 'c', 'c']
>>> list2 = ['x', 'b', 'a', 'x', 'c', 'y', 'c']
>>> set(list1).issubset(list2)
True
如果你需要检查第二个列表中的每个元素出现的次数是否至少和第一个列表中的一样多,你可以使用Counter这个类型,并定义你自己的子集关系:
>>> from collections import Counter
>>> def counterSubset(list1, list2):
c1, c2 = Counter(list1), Counter(list2)
for k, n in c1.items():
if n > c2[k]:
return False
return True
>>> counterSubset(list1, list2)
True
>>> counterSubset(list1 + ['a'], list2)
False
>>> counterSubset(list1 + ['z'], list2)
False
如果你已经有了计数器(这可能是存储数据的一个有用的替代方案),你也可以把它写成一行代码:
>>> all(n <= c2[k] for k, n in c1.items())
True