# How to efficiently compare two unordered lists (not sets)?

## Question:

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

a & b should be considered equal, because they have exactly the same elements, only in different order.

The thing is, my actual lists will consist of objects (my class instances), not integers.

You can sort both:

``````sorted(a) == sorted(b)
``````

A counting sort could also be more efficient (but it requires the object to be hashable).

``````>>> from collections import Counter
>>> a = [1, 2, 3, 1, 2, 3]
>>> b = [3, 2, 1, 3, 2, 1]
>>> print (Counter(a) == Counter(b))
True
``````

The best way to do this is by sorting the lists and comparing them. (Using `Counter` won’t work with objects that aren’t hashable.) This is straightforward for integers:

``````sorted(a) == sorted(b)
``````

It gets a little trickier with arbitrary objects. If you care about object identity, i.e., whether the same objects are in both lists, you can use the `id()` function as the sort key.

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

(In Python 2.x you don’t actually need the `key=` parameter, because you can compare any object to any object. The ordering is arbitrary but stable, so it works fine for this purpose; it doesn’t matter what order the objects are in, only that the ordering is the same for both lists. In Python 3, though, comparing objects of different types is disallowed in many circumstances — for example, you can’t compare strings to integers — so if you will have objects of various types, best to explicitly use the object’s ID.)

If you want to compare the objects in the list by value, on the other hand, first you need to define what “value” means for the objects. Then you will need some way to provide that as a key (and for Python 3, as a consistent type). One potential way that would work for a lot of arbitrary objects is to sort by their `repr()`. Of course, this could waste a lot of extra time and memory building `repr()` strings for large lists and so on.

``````sorted(a, key=repr) == sorted(b, key==repr)
``````

If the objects are all your own types, you can define `__lt__()` on them so that the object knows how to compare itself to others. Then you can just sort them and not worry about the `key=` parameter. Of course you could also define `__hash__()` and use `Counter`, which will be faster.

If you know the items are always hashable, you can use a `Counter()` which is O(n)
If you know the items are always sortable, you can use `sorted()` which is O(n log n)

In the general case you can’t rely on being able to sort, or has the elements, so you need a fallback like this, which is unfortunately O(n^2)

``````len(a)==len(b) and all(a.count(i)==b.count(i) for i in a)
``````

O(n): The Counter() method is best (if your objects are hashable):

``````def compare(s, t):
return Counter(s) == Counter(t)
``````

O(n log n): The sorted() method is next best (if your objects are orderable):

``````def compare(s, t):
return sorted(s) == sorted(t)
``````

O(n * n): If the objects are neither hashable, nor orderable, you can use equality:

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

Let a,b lists

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

No need to make them hashable or sort them.

I hope the below piece of code might work in your case :-

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

This will ensure that all the elements in both the lists `a` & `b` are same, regardless of whether they are in same order or not.

For better understanding, refer to my answer in this question

If the comparison is to be performed in a testing context, use `assertCountEqual(a, b)` (`py>=3.2`) and `assertItemsEqual(a, b)` (`2.7<=py<3.2`).

Works on sequences of unhashable objects too.

If you have to do this in tests:
https://docs.python.org/3.5/library/unittest.html#unittest.TestCase.assertCountEqual

`assertCountEqual(first, second, msg=None)`

Test that sequence first contains the same elements as second, regardless of their order. When they don’t, an error message listing the differences between the sequences will be generated.

Duplicate elements are not ignored when comparing first and second. It verifies whether each element has the same count in both sequences. Equivalent to: assertEqual(Counter(list(first)), Counter(list(second))) but works with sequences of unhashable objects as well.

New in version 3.2.

Outside of tests I would recommend the `Counter` method.

If the list contains items that are not hashable (such as a list of objects) you might be able to use the Counter Class and the id() function such as:

``````from collections import Counter
...
if Counter(map(id,a)) == Counter(map(id,b)):
print("Lists a and b contain the same objects")
``````

You can write your own function to compare the lists.

Let’s get two lists.

``````list_1=['John', 'Doe']
list_2=['Doe','Joe']
``````

Firstly, we define an empty dictionary, count the list items and write in the dictionary.

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

``````

After that, we’ll compare both lists by using the following function.

``````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)
``````
``````from collections import defaultdict

def _list_eq(a: list, b: list) -> bool:
if len(a) != len(b):
return False
b_set = set(b)
a_map = defaultdict(lambda: 0)
b_map = defaultdict(lambda: 0)
for item1, item2 in zip(a, b):
if item1 not in b_set:
return False
a_map[item1] += 1
b_map[item2] += 1
return a_map == b_map
``````

Sorting can be quite slow if the data is highly unordered (timsort is extra good when the items have some degree of ordering). Sorting both also requires fully iterating through both lists.

Rather than mutating a list, just allocate a set and do a left–>right membership check, keeping a count of how many of each item exist along the way:

• If the two lists are not the same length you can short circuit and return `False` immediately.
• If you hit any item in list `a` that isn’t in list `b` you can return `False`
• If you get through all items then you can compare the values of `a_map` and `b_map` to find out if they match.

This allows you to short-circuit in many cases long before you’ve iterated both lists.

plug in this:

``````def lists_equal(l1: list, l2: list) -> bool:
"""

import collections
compare = lambda x, y: collections.Counter(x) == collections.Counter(y)
ref:
- https://stackoverflow.com/questions/9623114/check-if-two-unordered-lists-are-equal
- https://stackoverflow.com/questions/7828867/how-to-efficiently-compare-two-unordered-lists-not-sets
"""
compare = lambda x, y: collections.Counter(x) == collections.Counter(y)
set_comp = set(l1) == set(l2)  # removes duplicates, so returns true when not sometimes :(
multiset_comp = compare(l1, l2)  # approximates multiset
return set_comp and multiset_comp  #set_comp is gere in case the compare function doesn't work
``````
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.