Python 有序子集检验
我想测试一个有序集是否是一个更大有序集的子集。我使用元组和Python 有序子集检验,python,tuples,subset,itertools,Python,Tuples,Subset,Itertools,我想测试一个有序集是否是一个更大有序集的子集。我使用元组和itertools。组合: def subset_test(a, b): return a in itertools.combinations(b, len(a)) 比如说, >>> subset_test((0, 1, 2), (0, 3, 1, 4, 2)) True >>> subset_test((0, 1, 2), (0, 3, 2, 4, 1)) False 它可以工作,但在测试
itertools。组合
:
def subset_test(a, b):
return a in itertools.combinations(b, len(a))
比如说,
>>> subset_test((0, 1, 2), (0, 3, 1, 4, 2))
True
>>> subset_test((0, 1, 2), (0, 3, 2, 4, 1))
False
它可以工作,但在测试大元组时速度很慢。一种简单的方法
>>> a = (0, 1, 2)
>>> b = (0, 3, 1, 4, 2)
>>> filter(set(a).__contains__, b) == a
True
为了提高效率,请使用itertools
>>> from itertools import ifilter, imap
>>> from operator import eq
>>> all(imap(eq, ifilter(set(a).__contains__, b), a))
True
这应该让你开始
>>> A = (0, 1, 2)
>>> B = (0, 3, 1, 4, 2)
>>> b_idxs = {v:k for k,v in enumerate(B)}
>>> idxs = [b_idxs[i] for i in A]
>>> idxs == sorted(idxs)
True
如果列表理解抛出了一个
键错误
,那么答案显然也是假
,这应该很快,但我想到了一个更快的错误,我希望很快就搞定:
def is_sorted_subset(A, B):
try:
subset = [B.index(a) for a in A]
return subset == sorted(subset)
except ValueError:
return False
更新:这是我答应过的更快的
def is_sorted_subset(A, B):
max_idx = -1
try:
for val in A:
idx = B[max_idx + 1:].index(val)
if max(idx, max_idx) == max_idx:
return False
max_idx = idx
except ValueError:
return False
return True
这里有一个线性时间方法(在最长的集合中),它不需要任何散列。它利用了这样一个事实,即由于两个集合都已排序,因此集合中较早的项目不需要重新检查:
>>> def subset_test(a, b):
... b = iter(b)
... try:
... for i in a:
... j = b.next()
... while j != i:
... j = b.next()
... except StopIteration:
... return False
... return True
...
一些测试:
>>> subset_test((0, 1, 2), (0, 3, 1, 4, 2))
True
>>> subset_test((0, 2, 1), (0, 3, 1, 4, 2))
False
>>> subset_test((0, 1, 5), (0, 3, 1, 4, 2))
False
>>> subset_test((0, 1, 4), (0, 3, 1, 4, 2))
True
我很确定这是对的,如果你发现任何问题,请告诉我 这个怎么样
>>> a = (0, 1, 2)
>>> b = (0, 3, 1, 4, 2)
>>> set(a).issubset(set(b))
True
在本例中,a和b具有有序且唯一的元素,它检查a是否是b的子集。这是你想要的吗
编辑:
根据@Marcos da Silva Sampaio:“我想测试A是否是有序集B的子集。”
但情况并非如此:
>>> a = (2, 0, 1)
>>> b = (0, 3, 1, 4, 2)
>>> set(b).issuperset(a)
True
在这种情况下,a的顺序并不重要。您可以简单地使用迭代器跟踪B中的位置
>>> A = (0, 1, 2)
>>> B = (0, 3, 1, 4, 2)
>>> b_iter = iter(B)
>>> all(a in b_iter for a in A)
True
是的,贾米拉克。我更新了问题。@senderle,你能建议一个更好的术语吗?我想测试A是否是有序集B的子集。关于您的原始代码,不需要调用
list
,您也可以检查生成器中的成员身份,它将保存一次组合运行。谢谢,@jamylak。我再次更新了这个问题。请注意,如果B
很大,这可能会变慢,因为列表。索引是O(N)a
的元素可能没有正确排序,例如(2,1,0)
中的(0,3,1,4,2)
哦,哇!我明白为什么会这样,但看起来像是黑魔法。在这种情况下,
中的行为是否得到保证?标准中是否有要求中的使用线性迭代并在找到匹配项时停止?我无法想象它会以任何其他方式完成,但对于“一般情况”来说可能仍然是一个问题。@MadPhysician,当然不是<
中的code>调用底层的\uuuuuu contains\uuuu
方法。例如,对于dict
,
中的肯定不是线性搜索。另一方面,它必须是对迭代器的线性搜索-这意味着什么呢?或者过滤器(functools.partial(operator.contains,a),b)
等等@gnibler您认为这样做更好还是在这种情况下使用特殊方法可以?特殊方法版本的运行速度似乎快了一倍左右。列表理解似乎是最慢的。