[python] How to assert two list contain the same elements in Python?

When writing test cases, I often need to assert that two list contain the same elements without regard to their order.

I have been doing this by converting the lists to sets.

Is there any simpler way to do this?

EDIT:

As @MarkDickinson pointed out, I can just use TestCase.assertItemsEqual.

Notes that TestCase.assertItemsEqual is new in Python2.7. If you are using an older version of Python, you can use unittest2 - a backport of new features of Python 2.7.

This question is related to python unit-testing

The answer is


As of Python 3.2 unittest.TestCase.assertItemsEqual(doc) has been replaced by unittest.TestCase.assertCountEqual(doc) which does exactly what you are looking for, as you can read from the python standard library documentation. The method is somewhat misleadingly named but it does exactly what you are looking for.

a and b have the same elements in the same number, regardless of their order

Here a simple example which compares two lists having the same elements but in a different order.

  • using assertCountEqual the test will succeed
  • using assertListEqual the test will fail due to the order difference of the two lists

Here a little example script.

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()

Side Note : Please make sure that the elements in the lists you are comparing are sortable.


Given

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

In Python >= 3.0

assertCountEqual(l1, l2) # True

In Python >= 2.7, the above function was named:

assertItemsEqual(l1, l2) # True

In Python < 2.7

import unittest2
assertItemsEqual(l1, l2) # True

Via six module (Any Python version)

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

Converting your lists to sets will tell you that they contain the same elements. But this method cannot confirm that they contain the same number of all elements. For example, your method will fail in this case:

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

You are likely better off sorting the two lists and comparing them:

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

Note that this does not alter the structure/contents of the two lists. Rather, the sorting creates two new lists


Slightly faster version of the implementation (If you know that most couples lists will have different lengths):

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

Comparing:

>>> 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

Needs ensure library but you can compare list by:

ensure([1, 2]).contains_only([2, 1])

This will not raise assert exception. Documentation of thin is really thin so i would recommend to look at ensure's codes on github