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您认为这样做更好还是在这种情况下使用特殊方法可以?特殊方法版本的运行速度似乎快了一倍左右。列表理解似乎是最慢的。