确定2个列表是否具有相同的元素,而不pipe顺序如何?

对不起,这个简单的问题,但我很难find答案。

当我比较2个列表时,我想知道它们是否“相等”,因为它们具有相同的内容,但顺序不同。

例如:

x = ['a', 'b'] y = ['b', 'a'] 

我想x == y评估为True

您可以简单地检查具有x和y元素的多重集是否相等:

 import collections collections.Counter(x) == collections.Counter(y) 

这要求元素是可散列的; 运行时将在O(n) ,其中n是列表的大小。

如果元素也是唯一的,你也可以转换成集(相同的渐近运行时,可能在实践中快一点):

 set(x) == set(y) 

如果元素不可sorting,但可sorting,则另一种替代( O(n log n)运行时)是

 sorted(x) == sorted(y) 

如果元素既不可sorting也不可sorting,那么可以使用下面的帮助函数。 请注意,它会很慢( O(n²) ),通常应该用在难以分解和不可分解的元素之外。

 def equal_ignore_order(a, b): """ Use only when elements are neither hashable nor sortable! """ unmatched = list(b) for element in a: try: unmatched.remove(element) except ValueError: return False return not unmatched 

确定2个列表是否具有相同的元素,而不pipe顺序如何?

从你的例子推断:

 x = ['a', 'b'] y = ['b', 'a'] 

这些列表中的元素不会被重复(它们是唯一的)以及可散列的(哪些string和其他某些不可变的python对象), 最直接和计算效率最高的答案是使用Python的内置集合(在语义上类似于math你可能已经在学校了解到)。

 set(x) == set(y) # prefer this if elements are hashable 

在元素可散列但不唯一的情况下, collections.Counter语义上也可以作为一个multiset使用,但速度要慢得多

 from collections import Counter Counter(x) == Counter(y) 

喜欢使用sorted

 sorted(x) == sorted(y) 

如果元素是可订购的。 这将解释非唯一或不可哈希的情况,但这可能比使用集合要慢得多。

实证实验

经验实验得出结论,人们应该喜欢set ,然后sorted 。 只有selectCounter如果你需要其他的东西,如计数或进一步使用作为multiset。

第一次设置:

 import timeit import random from collections import Counter data = [str(random.randint(0, 100000)) for i in xrange(100)] data2 = data[:] # copy the list into a new one def sets_equal(): return set(data) == set(data2) def counters_equal(): return Counter(data) == Counter(data2) def sorted_lists_equal(): return sorted(data) == sorted(data2) 

并testing:

 >>> min(timeit.repeat(sets_equal)) 13.976069927215576 >>> min(timeit.repeat(counters_equal)) 73.17287588119507 >>> min(timeit.repeat(sorted_lists_equal)) 36.177085876464844 

所以我们看到比较集是最快的解决scheme,比较sorting列表是第二快。

这似乎工作,虽然可能繁琐的大型名单。

 >>> A = [0, 1] >>> B = [1, 0] >>> C = [0, 2] >>> not sum([not i in A for i in B]) True >>> not sum([not i in A for i in C]) False >>> 

但是,如果每个列表必须包含其他所有元素,那么上面的代码是有问题的。

 >>> A = [0, 1, 2] >>> not sum([not i in A for i in B]) True 

len(A) != len(B)并且在这个例子中len(A) > len(B) 。 为了避免这种情况,你可以添加一个语句。

 >>> not sum([not i in A for i in B]) if len(A) == len(B) else False False 

还有一件事,我在亚伦·霍尔(Aaron Hall)在他的post中所用的相同条件下,用timeit.repeat作为基准。 怀疑,结果令人失望。 我的方法是最后一个。 set(x) == set(y)它是。

 >>> def foocomprehend(): return not sum([not i in data for i in data2]) >>> min(timeit.repeat('fooset()', 'from __main__ import fooset, foocount, foocomprehend')) 25.2893661496 >>> min(timeit.repeat('foosort()', 'from __main__ import fooset, foocount, foocomprehend')) 94.3974742993 >>> min(timeit.repeat('foocomprehend()', 'from __main__ import fooset, foocount, foocomprehend')) 187.224562545 

正如上面的评论中所提到的,一般情况是一个痛苦。 如果所有项目都是可sorting的或者所有项目都是可sorting的,则相当容易。 不过,我最近不得不尝试解决一般情况。 这是我的解决scheme。 在发布之后,我意识到这是对第一遍错过的解决scheme的重复。 无论如何,如果你使用片而不是list.remove(),你可以比较不可变的序列。

 def sequences_contain_same_items(a, b): for item in a: try: i = b.index(item) except ValueError: return False b = b[:i] + b[i+1:] return not b