我需要验证列表是否是另一个列表的子集-我想要的只是布尔返回值。
在相交之后在较小列表上测试相等性是最快的方法吗?鉴于需要比较的数据集数量,性能至关重要。
根据讨论添加更多事实:
在许多测试中,两个列表中的两个列表是否相同?它作为静态查找表之一来执行。
需要列表吗?事实并非如此-静态查找表可以是执行效果最好的任何内容。动态命令是一个字典,我们从中提取密钥以执行静态查找。
在这种情况下,最佳解决方案是什么?
我需要验证列表是否是另一个列表的子集-我想要的只是布尔返回值。
在相交之后在较小列表上测试相等性是最快的方法吗?鉴于需要比较的数据集数量,性能至关重要。
根据讨论添加更多事实:
在许多测试中,两个列表中的两个列表是否相同?它作为静态查找表之一来执行。
需要列表吗?事实并非如此-静态查找表可以是执行效果最好的任何内容。动态命令是一个字典,我们从中提取密钥以执行静态查找。
在这种情况下,最佳解决方案是什么?
Answers:
Python为此提供的性能函数是set.issubset
。但是,它确实有一些限制,使得不清楚是否是您问题的答案。
列表可能包含多个项目并具有特定顺序。一套没有。此外,设置仅适用于可哈希对象。
您是在询问子集还是子序列(这意味着您需要一个字符串搜索算法)?在许多测试中,两个列表中的两个列表是否相同?列表中包含哪些数据类型?而且,这是否需要列出清单?
您的其他文章与字典和列表相交,使类型更清晰,并且确实推荐使用字典键视图来实现类似集合的功能。在那种情况下,之所以可以工作是因为字典键的行为就像一个集合(以至于在我们使用Python进行集合之前,我们都使用字典)。一个人想知道问题如何在三个小时内变得不那么具体。
>>> 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
为set而不转换为set 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)
issubset
就是检查参数是否为set
/ frozenset
,如果不是,它将其转换为临时变量set
进行比较,运行检查,然后丢弃该临时变量set
。时间差异(如果有的话)将是LEGB查找成本差异很小的一个因素(set
第二次查找比现有属性的属性查找更昂贵set
),但是对于足够大的输入来说,这主要是洗钱。
one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]
all(x in two for x in one)
说明:生成器通过遍历列表one
检查该项是否在list中来创建布尔值two
。 如果每个项目都是真实的,则返回,否则all()
返回。True
False
还有一个优点是all
,在缺少元素的第一个实例上返回False,而不必处理每个项目。
set(one).issubset(set(two))
是一个很好的解决方案。使用我发布的解决方案,如果定义了正确的比较运算符,则应该可以将其与任何对象一起使用。
all
正确短路,而后者将执行所有检查,即使从第一次检查中可以清楚得知测试将失败。只需放下方括号即可all(x in two for x in one)
。
假设项目是可哈希的
>>> 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)个项目要进行迭代和检查。
集合论不适用于列表,因为重复使用集合论会导致错误的答案。
例如:
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
如果我迟到聚会请原谅。;)
要检查一个set A
是否是set B
,Python
具有A.issubset(B)
和的子集A <= B
。它set
只能工作,而且效果很好,但是内部实现的复杂性是未知的。参考:https : //docs.python.org/2/library/sets.html#set-objects
我想出了一种算法来检查是否list A
是list B
以下注释的子集。
sort
先比较两个列表,然后再比较要符合子集条件的元素。break
在loop
当第二列表元素的值B[j]
比第一个列表元素的值A[i]
。last_index_j
用于启动loop
在list B
其最后一次离开。它有助于避免从的开头开始进行比较
list B
(您可能会不必要地list B
从index 0
随后的开始iterations
)进行比较。O(n ln n)
排序列表和O(n)
检查子集都将很复杂。
O(n ln n) + O(n ln n) + O(n) = O(n ln n)
。
代码中有很多print
语句,以查看每个处iteration
发生了什么loop
。这些仅用于理解。
检查一个列表是否是另一个列表的子集
is_subset = True;
A = [9, 3, 11, 1, 7, 2];
B = [11, 4, 6, 2, 15, 1, 9, 8, 5, 3];
print(A, B);
# skip checking if list A has elements more than list B
if len(A) > len(B):
is_subset = False;
else:
# complexity of sorting using quicksort or merge sort: O(n ln n)
# use best sorting algorithm available to minimize complexity
A.sort();
B.sort();
print(A, B);
# complexity: O(n^2)
# for a in A:
# if a not in B:
# is_subset = False;
# break;
# complexity: O(n)
is_found = False;
last_index_j = 0;
for i in range(len(A)):
for j in range(last_index_j, len(B)):
is_found = False;
print("i=" + str(i) + ", j=" + str(j) + ", " + str(A[i]) + "==" + str(B[j]) + "?");
if B[j] <= A[i]:
if A[i] == B[j]:
is_found = True;
last_index_j = j;
else:
is_found = False;
break;
if is_found:
print("Found: " + str(A[i]));
last_index_j = last_index_j + 1;
break;
else:
print("Not found: " + str(A[i]));
if is_found == False:
is_subset = False;
break;
print("subset") if is_subset else print("not subset");
输出量
[9, 3, 11, 1, 7, 2] [11, 4, 6, 2, 15, 1, 9, 8, 5, 3]
[1, 2, 3, 7, 9, 11] [1, 2, 3, 4, 5, 6, 8, 9, 11, 15]
i=0, j=0, 1==1?
Found: 1
i=1, j=1, 2==1?
Not found: 2
i=1, j=2, 2==2?
Found: 2
i=2, j=3, 3==3?
Found: 3
i=3, j=4, 7==4?
Not found: 7
i=3, j=5, 7==5?
Not found: 7
i=3, j=6, 7==6?
Not found: 7
i=3, j=7, 7==8?
not subset
下面的代码检查给定集合是否为另一个集合的“适当子集”
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
如果您要问一个列表是否“包含”在另一个列表中,则:
>>>if listA in listB: return True
如果您要询问listA中的每个元素在listB中是否具有相等数量的匹配元素,请尝试:
all(True if listA.count(item) <= listB.count(item) else False for item in listA)