Как утверждать два списка содержат одни и те же элементы в Python?

При написании тестовых примеров мне часто приходится утверждать, что два списка содержат одни и те же элементы без учета их порядка.

Я делаю это, преобразовывая списки в наборы.

Есть ли более простой способ сделать это?

ИЗМЕНИТЬ

Как заметил @MarkDickinson, я могу просто использовать TestCase.assertItemsEqual.

Заметьте, что TestCase.assertItemsEqual является новым в Python2.7. Если вы используете более старую версию Python, вы можете использовать unittest2 - резерв новых возможностей Python 2.7.

Ответ 1

Немного более быстрая версия реализации (если вы знаете, что большинство списков пар будут иметь разную длину):

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

Ответ 2

Начиная с Python 3.2 unittest.TestCase.assertItemsEqual (doc) был заменен на unittest.TestCase.assertCountEqual (doc), который делает именно то, что вы ищете, как вы можете прочитать из документации стандартной библиотеки python. Метод несколько неверно назван, но он делает именно то, что вы ищете.

a и b имеют одинаковые элементы в одинаковом количестве, независимо от их порядка

Вот простой пример, который сравнивает два списка, имеющие одинаковые элементы, но в другом порядке.

  • используя assertCountEqual тест пройдёт успешно
  • при использовании assertListEqual тест не 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()

Примечание: пожалуйста, убедитесь, что элементы в списках, которые вы сравниваете, являются сортируемыми.

Ответ 3

Дано

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

В Python> = 3.0

assertCountEqual(l1, l2) # True

В Python> = 2.7 указанная выше функция была названа так:

assertItemsEqual(l1, l2) # True

В Python <2,7

import unittest2
assertItemsEqual(l1, l2) # True

Через six модулей (любая версия Python)

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

Ответ 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

Обратите внимание, что это не изменяет структуру/содержимое двух списков. Скорее, сортировка создает два новых списка

Ответ 5

Требуется обеспечить библиотеку, но вы можете сравнить список по:

обеспечить ([1, 2]). contains_only ([2, 1])

Это не приведет к возникновению исключения. Документация тонких очень тонкая, поэтому я бы рекомендовал посмотреть обеспечить коды на github