>>> a = [1, 3, 5]
>>> b = [1, 3, 5, 8]
>>> c = [3, 5, 9]
>>> set(a) <= set(b)
True
>>> set(c) <= set(b)
False
>>> a = ['yes', 'no', 'hmm']
>>> b = ['yes', 'no', 'hmm', 'well']
>>> c = ['sorry', 'no', 'hmm']
>>>
>>> set(a) <= set(b)
True
>>> set(c) <= set(b)
False
set(a).issubset(b)
,因为在这种情况下,你只将 a
转换为集合而不转换 b
,从而节省时间。 你可以使用timeit
比较这两个命令消耗的时间。例如:timeit.repeat('set(a)<set(b)', 'a = [1,3,5]; b = [1,3,5,7]', number=1000)
和 timeit.repeat('set(a).issubset(b)', 'a = [1,3,5]; b = [1,3,5,7]', number=1000)
。 - Yulan Liuissubset
的第一件事就是检查参数是否为set
/frozenset
,如果不是,它会将其转换为一个临时的set
用于比较,然后运行检查,最后丢弃临时的set
。时间差异(如果有的话)可能与LEGB查找成本(第二次查找set
比现有set
上的属性查找更昂贵)的小差异有关,但对于足够大的输入来说,这基本上是相同的。 - ShadowRanger示例:
a = {1,2}
b = {1,2,3}
a.issubset(b) # True
a = {1,2,4}
b = {1,2,3}
a.issubset(b) # False
Python提供的高效函数是set.issubset
。然而,它有一些限制使得不清楚它是否是你问题的答案。
列表可以包含多个相同项并具有特定顺序。集合没有。此外,集合只对可哈希对象有效。
你是在询问子集还是子序列(这意味着你需要一种字符串搜索算法)?两个列表中是否会有很多个测试?列表中包含的数据类型是什么?而且,它必须是一个列表吗?
您的另一篇文章澄清了类型,并获得了使用字典键视图作为其类似于集合功能的建议。在那种情况下,因为字典键行为类似于集合(在Python中没有集合之前我们使用字典),所以已知可以正常工作。人们想知道问题如何在三小时内变得不太具体。
one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]
all(x in two for x in one)
说明:该生成器通过循环遍历列表 one
并检查该项是否在列表 two
中,创建布尔值。如果每一项都为真,则 all()
返回 True
,否则返回 False
。
all
的另一个优点是,它在遇到缺失元素的第一个实例时返回False,而无需处理每个项。
set(one).issubset(set(two))
是一个很好的解决方案。使用我发布的解决方案,只要对象有适当定义的比较运算符,就可以将其应用于任何对象。 - voidnologoall
正确地进行短路,而后者将执行所有检查,即使从第一个检查中就可以清楚地知道测试会失败。只需删除方括号即可获得all(x in two for x in one)
。 - ShadowRanger假设这些项是可哈希的
>>> from collections import Counter
>>> not Counter([1, 2]) - Counter([1])
False
>>> not Counter([1, 2]) - Counter([1, 2])
True
>>> not Counter([1, 2, 2]) - Counter([1, 2])
False
如果您不关心重复项,例如 [1, 2, 2]
和 [1, 2]
,那么只需使用:
>>> set([1, 2, 2]).issubset([1, 2])
True
测试交集后较小列表的等式是否是最快的方法?使用.issubset
是最快的方式。在测试issubset
之前检查长度不会提高速度,因为仍需要迭代并检查O(N + M)个项。另一种解决方案是使用 intersection
。
one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]
set(one).intersection(set(two)) == set(one)
集合的交集包含了第一个集合
(或者)
one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]
set(one) & (set(two)) == set(one)
集合论对于列表来说是不适当的,因为使用集合论会导致重复项产生错误答案。
例如:
a = [1, 3, 3, 3, 5]
b = [1, 3, 3, 4, 5]
set(b) > set(a)
“没有意义”是错误的。是的,它会给出错误的答案,但这是不正确的,因为集合理论只是在比较:1、3、5与1、3、4、5。必须包括所有重复项。
相反,您必须计算每个项目的每个出现次数,并进行大于等于检查。这并不是非常昂贵,因为它不使用O(N^2)操作,也不需要快速排序。
#!/usr/bin/env python
from collections import Counter
def containedInFirst(a, b):
a_count = Counter(a)
b_count = Counter(b)
for key in b_count:
if a_count.has_key(key) == False:
return False
if b_count[key] > a_count[key]:
return False
return True
a = [1, 3, 3, 3, 5]
b = [1, 3, 3, 4, 5]
print "b in a: ", containedInFirst(a, b)
a = [1, 3, 3, 3, 4, 4, 5]
b = [1, 3, 3, 4, 5]
print "b in a: ", containedInFirst(a, b)
$ python contained.py
b in a: False
b in a: True
one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]
set(x in two for x in one) == set([True])
如果 list1 在 list2 中:
(x in one for x in two)
生成一个由True
组成的列表。
当我们执行 set(x in one for x in two)
时,只有一个元素(True)。
[*set()][index]
来获取元素。这种方法比其他方法要慢得多。one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]
result = set(x in two for x in one)
[*result][0] == True
或者只使用len和set函数
len(set(a+b)) == len(set(a))
def is_proper_subset(set, superset):
return all(x in superset for x in set) and len(set)<len(superset)
大多数解决方案都认为列表中没有重复项。如果您的列表中有重复项,可以尝试以下方法:
def isSubList(subList,mlist):
uniqueElements=set(subList)
for e in uniqueElements:
if subList.count(e) > mlist.count(e):
return False
# It is sublist
return True
它确保子列表永远不会有与列表不同的元素或更多的共同元素。
lst=[1,2,2,3,4]
sl1=[2,2,3]
sl2=[2,2,2]
sl3=[2,5]
print(isSubList(sl1,lst)) # True
print(isSubList(sl2,lst)) # False
print(isSubList(sl3,lst)) # False