Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 确定两个列表是否具有相同的元素,而不考虑顺序?_Python_List_Equality_Python 2.x - Fatal编程技术网

Python 确定两个列表是否具有相同的元素,而不考虑顺序?

Python 确定两个列表是否具有相同的元素,而不考虑顺序?,python,list,equality,python-2.x,Python,List,Equality,Python 2.x,很抱歉问这么简单的问题,但我很难找到答案 当我比较两个列表时,我想知道它们是否“相等”,因为它们的内容相同,但顺序不同 例: 我希望x==y计算为True您只需检查元素为x和y的多集是否相等: import collections collections.Counter(x) == collections.Counter(y) 这要求元素是可散列的;运行时将处于O(n),其中n是列表的大小 如果元素也是唯一的,还可以转换为集合(相同的渐近运行时,在实践中可能会快一点): 如果元素不是可散列的,

很抱歉问这么简单的问题,但我很难找到答案

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

例:


我希望
x==y
计算为
True

您只需检查元素为x和y的多集是否相等:

import collections
collections.Counter(x) == collections.Counter(y)
这要求元素是可散列的;运行时将处于
O(n)
,其中
n
是列表的大小

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

如果元素不是可散列的,而是可排序的,则可以使用另一种选择(运行时在
O(n log n)

如果元素既不可散列也不可排序,则可以使用以下helper函数。请注意,它将非常缓慢(
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
确定两个列表是否具有相同的元素,无论顺序如何?

从你的例子推断:

x = ['a', 'b']
y = ['b', 'a']
列表中的元素不会重复(它们是唯一的)也不会散列(哪些字符串和其他某些不可变的python对象是散列的),最直接、计算效率最高的答案是使用python的内置集(在语义上类似于你在学校学过的数学集)

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

首选使用排序的

sorted(x) == sorted(y) 
如果元素是可排序的。这可以解释非唯一或不可散列的情况,但这可能比使用集合慢得多

经验实验 一项实证实验得出结论,人们应该更喜欢
集合
,然后再
排序
。如果您需要计数或进一步用作多集,请仅选择计数器

第一次设置:

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)
和测试:

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

因此,我们发现比较集合是最快的解决方案,比较排序列表是第二快的解决方案。

这似乎是可行的,但对于大型列表来说可能很麻烦

>>> 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
还有一件事,我用timeit.repeat对我的解决方案进行了基准测试,测试条件与Aaron Hall在其帖子中使用的相同。正如人们所怀疑的那样,结果令人失望。我的方法是最后一种<代码>设置(x)=设置(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

如上文评论所述,一般情况是令人痛苦的。如果所有项都是可散列的,或者所有项都是可排序的,那么这就相当容易了。然而,我最近不得不尝试解决一般情况。这是我的解决办法。我在发布后意识到,这是一个重复的解决方案上面,我错过了第一关。无论如何,如果使用切片而不是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

不应该感到惊讶,因为您的方法是O(N^2),它比O(N)或O(N*logn)大得多。对于B(N个元素)的每个元素,它检查A(N个元素)的所有元素。检查的数量是N*N。如果您有列表
[1,1,8]
[1,8,8]
,那么使用集合是不适用的,因为元素实际上是不同的@这在我的回答中不是很明显吗?我一定是读过头了。我的错。
>>> 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
>>> not sum([not i in A for i in B]) if len(A) == len(B) else False
False
>>> 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
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