在Python中断言没有顺序的列表相等列表

时间:2015-07-19 13:48:05

标签: python python-3.x

断言两个列表列表的最佳方法是否相同而不重要的顺序?例如这两个列表是相同的:

a = [[1,2], [3,4]]
b = [[4,3], [2,1]]

assert lists_equal_without_order(a, b)  # True

如何使用Python的现有断言来实现lists_equal_without_order

6 个答案:

答案 0 :(得分:2)

一个仅适用于一系列假设的版本:

def lists_equal_without_order(a, b):
    """
    We don't care about duplicates in list comparison or the sublist comparison.
    * [1,2,2] === [1,1,2]  # True
    * [[1,1], [1,1]] == [[1,1]] # True
    The element lists are either the same length or we don't care about duplicates
    * [1,1,1] === [1]  # True
    """
    for l1 in a:
        check_list = frozenset(l1)
        if not any(check_list.issuperset(l2) for l2 in b):
            return False
    return True

a = [[1,2], [3,4]]
b = [[4,3], [2,1]]

print lists_equal_without_order(a, b)  # True

a = [[1,1], [2,2]]
b = [[1,2], [2,1]]

print lists_equal_without_order(a, b)  # False

一个弄乱原始列表的版本:

def lists_equal_without_order(a, b):
    """
    This will manipulate the original lists.
    """
    for l1 in a:
        l1.sort()
        for l2 in b:
            l2.sort()
            if l1 == l2:
                b.remove(l2)
                break
        else:
            return False
    return True

a = [[1,2], [3,4]]
b = [[4,3], [2,1]]

print lists_equal_without_order(a, b)  # True

a = [[1,1], [2,2]]
b = [[1,2], [2,1]]

print lists_equal_without_order(a, b)  # False

与计数器完全匹配的一个版本,但不需要在内存中保留2个列表副本:

from collections import Counter

def lists_equal_without_order(a, b):
    """
    This will make sure the inner list contain the same, 
    but doesn't account for duplicate groups.
    """
    for l1 in a:
        check_counter = Counter(l1)
        if not any(Counter(l2) == check_counter for l2 in b):
            return False
    return True

a = [[1,2], [3,4]]
b = [[4,3], [2,1]]

print lists_equal_without_order(a, b)  # True

a = [[1,1], [2,2]]
b = [[1,2], [2,1]]

print lists_equal_without_order(a, b)  # False

答案 1 :(得分:1)

如果ab中的项目没有重复项,那么 您可以使用集合理解来收集每个项目的冻结集。 例如,

In [106]: {(frozenset(item)) for item in a}
Out[106]: {frozenset({1, 2}), frozenset({3, 4})}

然后测试这些集合是否相等:

In [107]: {(frozenset(item)) for item in a} == {(frozenset(item)) for item in b}
Out[107]: True

这是有效的,因为集合没有顺序,而frozensets是可散列的(因此可以是集合的元素)。如果没有重复项,那么冻结集相等会使[1,2][2,1]等效:

In [109]: frozenset([1,2]) == frozenset([2,1])
Out[109]: True

但请注意,如果有重复项,那么frozensets会使[1,1,2]等同于[2,2,1]

In [108]: frozenset([1,1,2]) == frozenset([1,2,2])
Out[108]: True

答案 2 :(得分:1)

如果性能不是一个因素,一个简单的解决方案是首先对内部列表进行排序,然后对外部列表进行排序,然后进行比较。

示例 -

def lewo(l1, l2):
    l1new = [sorted(i) for i in l1]
    l2new = [sorted(i) for i in l2]
    l1newsorted = sorted(l1new)
    l2newsorted = sorted(l2new)
    return l1newsorted == l2newsorted

或更简洁 -

def lewo(a, b):
    a_s, b_s = map(sorted, a), map(sorted, b)
    return sorted(a_s) == sorted(b_s)

答案 3 :(得分:1)

如果子列表中没有重复项(或者可以忽略重复项),则此方法有效:

def lists_equal_without_order(a, b):
    return set_repr(a) == set_repr(b)

def set_repr(x):
    return {frozenset(item) for item in x}

如果我们需要考虑子列表中的重复项,我们需要使用计数器代替frozensets:

from collections import Counter

def lists_equal_without_order(a, b):
    return counter_repr(a) == counter_repr(b)

def counter_repr(x):
    return {frozenset(Counter(item).items()) for item in x}

如果子列表本身可以多次出现(即如果外部列表包含重复项),我们可以使用计数器作为外部列表:

from collections import Counter

def lists_equal_without_order(a, b):
    return counter_repr(a) == counter_repr(b)

def counter_repr(x):
    return Counter(frozenset(Counter(item).items()) for item in x)

答案 4 :(得分:0)

按照列表的大小运行一个循环。

A =列出a;

B =列表b;

对于i从0开始运行:循环大小

{ Temp = a [i];

如果(集合B中有温度)     从B中删除临时文字;

}

如果B为空,则设置A = B;

否则 甲!= B

答案 5 :(得分:0)

另一种set/frozenset方法:

a = [[1,2], [3,4]]
b = [[4,3], [2,1]]

def lists_equal_without_order(lst0, lst1):
    set0 = set( frozenset(item) for item in lst0 )
    set1 = set( frozenset(item) for item in lst1 )
    return set0 == set1

print(lists_equal_without_order(a,b))

我不完全确定它涵盖了所有用例。适用于你给出的例子......