Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/338.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_Algorithm_List_Comparison - Fatal编程技术网

如何在Python中有效地比较两个无序列表(而不是集合)?

如何在Python中有效地比较两个无序列表(而不是集合)?,python,algorithm,list,comparison,Python,Algorithm,List,Comparison,a和b应该被认为是相等的,因为它们有完全相同的元素,只是顺序不同 问题是,我的实际列表将由对象(我的类实例)组成,而不是整数。您可以对两者进行排序: a = [1, 2, 3, 1, 2, 3] b = [3, 2, 1, 3, 2, 1] A也可能更有效(但它要求对象是可散列的) 最好的方法是对列表进行排序并进行比较。(使用计数器无法处理不可散列的对象。)这对于整数很简单: >>> from collections import Counter >>> a

a和b应该被认为是相等的,因为它们有完全相同的元素,只是顺序不同

问题是,我的实际列表将由对象(我的类实例)组成,而不是整数。

您可以对两者进行排序:

a = [1, 2, 3, 1, 2, 3]
b = [3, 2, 1, 3, 2, 1]
A也可能更有效(但它要求对象是可散列的)


最好的方法是对列表进行排序并进行比较。(使用
计数器
无法处理不可散列的对象。)这对于整数很简单:

>>> from collections import Counter
>>> a = [1, 2, 3, 1, 2, 3]
>>> b = [3, 2, 1, 3, 2, 1]
>>> print (Counter(a) == Counter(b))
True
使用任意对象会变得有点棘手。如果您关心对象标识,即两个列表中是否有相同的对象,则可以使用
id()
函数作为排序键

sorted(a) == sorted(b)
(在Python2.x中,您实际上不需要
key=
参数,因为您可以将任何对象与任何对象进行比较。排序是任意的,但很稳定,因此它可以很好地用于此目的;不管对象的顺序是什么,只是两个列表的排序是相同的。不过,在Python3中,比较不同类型的对象pes在许多情况下是不允许的——例如,您不能将字符串与整数进行比较——因此,如果您将拥有各种类型的对象,最好显式使用对象的ID。)

另一方面,如果要按值比较列表中的对象,首先需要定义“值”对对象的含义。然后需要某种方法将其作为键提供(对于Python 3,作为一致类型)。一种可能适用于许多任意对象的方法是按其
repr()排序
。当然,这可能会浪费大量额外的时间和内存来构建大型列表的
repr()
字符串等等

sorted(a, key=id) == sorted(b, key==id)

如果对象都是您自己的类型,您可以在它们上定义
\uu lt\uu()
,以便对象知道如何将自己与其他对象进行比较。然后您可以对它们进行排序,而不必担心
键=
参数。当然,您也可以定义
\uu散列()
并使用
计数器
,这将更快。

如果您知道项目总是可散列的,您可以使用一个
计数器()
,它是O(n)
如果您知道项目总是可排序的,那么可以使用
sorted()
,它是O(n log n)

在一般情况下,您不能依赖于能够排序或拥有元素,因此您需要这样的回退,不幸的是O(n^2)

O(n):该方法是最好的(如果您的对象是可散列的):

O(n log n):该方法是次优方法(如果您的对象是可订购的):

O(n*n):如果对象既不可散列也不可排序,则可以使用相等:

def compare(s, t):
    return sorted(s) == sorted(t)
让a,b列出

def compare(s, t):
    t = list(t)   # make a mutable copy
    try:
        for elem in s:
            t.remove(elem)
    except ValueError:
        return False
    return not t

无需对它们进行散列或排序。

我希望下面的代码可能适用于您的情况:-

def ass_equal(a,b):
try:
    map(lambda x: a.pop(a.index(x)), b) # try to remove all the elements of b from a, on fail, throw exception
    if len(a) == 0: # if a is empty, means that b has removed them all
        return True 
except:
    return False # b failed to remove some items from a
这将确保两个列表
a
b
中的所有元素都相同,无论它们的顺序是否相同


为了更好地理解,请参考我在

中的答案。如果要在测试环境中执行比较,请使用(
py>=3.2
)和(
2.7,如果必须在测试中执行此操作:

assertCountEqual(第一,第二,msg=None)

测试序列first是否包含与second相同的元素,而不考虑它们的顺序。如果它们不包含,则会生成一条错误消息,列出序列之间的差异

比较第一个和第二个时不会忽略重复的元素。它验证两个序列中的每个元素是否具有相同的计数。等效于:assertEqual(计数器(列表(第一)),计数器(列表(第二)),但也适用于不可损坏对象的序列

3.2版中的新版本

或在2.7中:


在测试之外,我建议使用
计数器
方法。

如果列表包含不可散列的项(例如对象列表),则可以使用和id()函数,例如:

if ((len(a) == len(b)) and
   (all(i in a for i in b))):
    print 'True'
else:
    print 'False'

您可以编写自己的函数来比较列表

我们来拿两份清单

from collections import Counter
...
if Counter(map(id,a)) == Counter(map(id,b)):
    print("Lists a and b contain the same objects")
首先,我们定义一个空字典,统计列表项并写入字典

list_1=['John', 'Doe'] 
list_2=['Doe','Joe']
之后,我们将使用以下函数比较两个列表

def count_list(list_items):
    empty_dict={}
    for list_item in list_items:
        list_item=list_item.strip()
        if list_item not in empty_dict:
            empty_dict[list_item]=1
        else:
            empty_dict[list_item]+=1
    return empty_dict


        

对象是如何比较的?实际列表的预期大小是多少?被比较的列表的大小是可比的还是非常不同的?您希望大多数列表匹配还是不匹配?可以选中
len()
s首先。计数器确实使用哈希,但对象本身并不是不可损坏的。您只需实现一个合理的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu也不适用于子集/超集测试中已覆盖比较运算符的集合。是的,但正如其他一些海报所述,这是O(n**2),因此仅当其他方法不起作用时才应使用。它还假设
a
支持
pop
(是可变的)和
索引
(是序列).Raymond的都不假设,而gnibbler的只假设序列。谢谢。我将每个对象转换为字符串,然后使用Counter()方法。嘿@Raymond,我最近在一次采访中遇到了这个问题,我使用了
sorted()
,不可否认不知道
计数器
。面试官坚持认为有一种更有效的方法,很明显我画了一张空白。在python 3中使用
timeit
模块进行了大量测试后,排序在整数列表中的速度始终更快。在1k个项目的列表中,速度大约慢1.5%,在短列表中,速度慢10%tems,慢7.5%。想法?对于短名单,大O分析通常是不相关的,因为时间由恒定因素决定。对于长名单,我怀疑你的基准测试有问题。对于100个整数,每个重复5次,我得到:127 usec
if ((len(a) == len(b)) and
   (all(i in a for i in b))):
    print 'True'
else:
    print 'False'
from collections import Counter
...
if Counter(map(id,a)) == Counter(map(id,b)):
    print("Lists a and b contain the same objects")
list_1=['John', 'Doe'] 
list_2=['Doe','Joe']
def count_list(list_items):
    empty_dict={}
    for list_item in list_items:
        list_item=list_item.strip()
        if list_item not in empty_dict:
            empty_dict[list_item]=1
        else:
            empty_dict[list_item]+=1
    return empty_dict


        
def compare_list(list_1, list_2):
    if count_list(list_1)==count_list(list_2):
        return True
    return False
compare_list(list_1,list_2)