【问题标题】:How to assert two list contain the same elements in Python? [duplicate]如何断言两个列表在 Python 中包含相同的元素? [复制]
【发布时间】:2012-09-30 14:05:36
【问题描述】:

在编写测试用例时,我经常需要断言两个列表包含相同的元素,而不考虑它们的顺序。

我一直在通过将列表转换为集合来做到这一点。

有没有更简单的方法来做到这一点?

编辑

正如@MarkDickinson 指出的,我可以使用TestCase.assertItemsEqual

注意TestCase.assertItemsEqual 是 Python2.7 中的新内容。 如果您使用的是旧版本的 Python,则可以使用 unittest2 - Python 2.7 新功能的反向移植。

【问题讨论】:

  • set(x) == set(y)简单吗?你能简单到什么程度?
  • @cdhowie:当列表中有冗余元素时,这将失败。
  • @inspectorG4dget 从最初的问题中不清楚这是否应该是一个失败案例。
  • 如果你是单元测试,TestCase.assertItemsEqual 有什么问题?
  • @MarkDickinson “不考虑他们的订单”。

标签: python unit-testing


【解决方案1】:

从 Python 3.2 开始,unittest.TestCase.assertItemsEqual(doc) 已被 unittest.TestCase.assertCountEqual(doc) 取代,这正是您所寻找的,正如您可以从 python standard library documentation 中读取的那样。该方法的名称有些误导,但它完全符合您的要求。

a 和 b 具有相同编号的相同元素,无论它们的顺序如何

这是一个简单的例子,它比较了两个具有相同元素但顺序不同的列表。

  • 使用assertCountEqual测试会成功
  • 使用assertListEqual,由于两个列表的顺序不同,测试会失败

这里有一个小示例脚本。

import unittest


class TestListElements(unittest.TestCase):
    def setUp(self):
        self.expected = ['foo', 'bar', 'baz']
        self.result = ['baz', 'foo', 'bar']

    def test_count_eq(self):
        """Will succeed"""
        self.assertCountEqual(self.result, self.expected)

    def test_list_eq(self):
        """Will fail"""
        self.assertListEqual(self.result, self.expected)

if __name__ == "__main__":
    unittest.main()

旁注:请确保您要比较的列表中的元素是可排序的。

【讨论】:

  • 谢谢。原来的名字更清楚了,我见过那个方法,但假设它检查了计数。
  • 有没有办法与“几乎相等”的列表进行比较?在给定错误的意义上,如果列表中的元素的差异在错误范围内,我想断言相等?
  • 谢谢。但是彻头彻尾误导,我会称之为!
  • 这是不正确的 - 尝试 self.assertCountEqual({1: [1, 2, 3]}, {1: [5, 6, 7]})
  • 注意 - 在 Python 2 中,您可以使用六库来执行 Six.assertCountEqual,以便将来进行任何 py3 升级:)
【解决方案2】:

较快的实现版本(如果您知道大多数情侣列表的长度不同):

def checkEqual(L1, L2):
    return len(L1) == len(L2) and sorted(L1) == sorted(L2)

比较:

>>> timeit(lambda: sorting([1,2,3], [3,2,1]))
2.42745304107666
>>> timeit(lambda: lensorting([1,2,3], [3,2,1]))
2.5644469261169434 # speed down not much (for large lists the difference tends to 0)

>>> timeit(lambda: sorting([1,2,3], [3,2,1,0]))
2.4570400714874268
>>> timeit(lambda: lensorting([1,2,3], [3,2,1,0]))
0.9596951007843018 # speed up

【讨论】:

  • 您的加速来自(1)无分支(有效),(2)len 排序前检查。 len 检查是 O(n),只有在它返回 False 时才有帮助。否则,通过添加两个线性通道(L1L2 各一个)会损害实际运行时间(而不是复杂性)。因此,虽然运行时复杂度仍然是 O(nlogn)(来自排序),但 O(n) 会影响此函数所需的秒数 return
  • @inspectorG4dget,添加比较(无分支差异)
  • 这正是我的意思。如果 OP 先验地知道他比较的大多数列表对的长度不等,那么你的实际上是一个更好的解决方案
  • @inspectorG4dget: len() 具有 O(1) 复杂度(恒定时间)。没有通过获取值。
  • 如果您的列表包含不可排序的类型,例如dict,则此方法不起作用。
【解决方案3】:

给定

l1 = [a,b]
l2 = [b,a]

In Python >= 3.0

assertCountEqual(l1, l2) # True

In Python >= 2.7,上面的函数被命名为:

assertItemsEqual(l1, l2) # True

In Python < 2.7

import unittest2
assertItemsEqual(l1, l2) # True

Via six module(任何 Python 版本)

import unittest
import six
class MyTest(unittest.TestCase):
    def test(self):
        six.assertCountEqual(self, self.l1, self.l2) # True

【讨论】:

  • 如果列表中只有唯一值 使用 set(l1)& set(2) 将它们转换为 set 并使用 assertSetEqual(l1, l2) 进行断言也有帮助。
  • +1 为您的解决方案@Abhijeet,因为它实际上检查列表的内容是否匹配,这对于比较一组唯一 ID 很有用。
  • 试试 self.assertCountEqual({1: [1, 2, 3]}, {1: [5, 6, 7]})
【解决方案4】:

将列表转换为集合会告诉您它们包含相同的元素。但是这种方法不能确认它们包含相同数量的所有元素。例如,您的方法在这种情况下会失败:

L1 = [1,2,2,3]
L2 = [1,2,3,3]

您最好对这两个列表进行排序并进行比较:

def checkEqual(L1, L2):
    if sorted(L1) == sorted(L2):
        print "the two lists are the same"
        return True
    else:
        print "the two lists are not the same"
        return False

请注意,这不会改变两个列表的结构/内容。相反,排序会创建两个新列表

【讨论】:

  • 如果我要将它封装在一个函数中,它的正确名称是什么?
  • “抽象/封装成一个函数”。编辑答案以将我的代码抽象为函数
  • 在我的商店中,我们使用 'assertElementsEqual',这对我们来说很有意义。
  • 如果列表包含“不可散列的元素”(例如字典),这将失败 - 不管这意味着什么:TypeError: unhashable type: 'dict'
【解决方案5】:

需要确保库,但您可以通过以下方式比较列表:

确保([1, 2]).contains_only([2, 1])

这不会引发断言异常。薄的文档真的很薄,所以我建议看看ensure's codes on github

【讨论】:

    猜你喜欢
    • 2012-08-23
    • 2012-10-26
    • 2011-05-26
    • 1970-01-01
    • 2021-07-05
    • 1970-01-01
    • 1970-01-01
    • 2017-09-10
    • 1970-01-01
    相关资源
    最近更新 更多