HOWTO · Python
How to Compare Lists in Python
Compare Python lists correctly by choosing ordered equality, Counter, set operations, or an order-preserving comprehension based on order and duplicates.
On this page
To compare two Python lists, first decide whether order and duplicate counts are meaningful. Use == for exact ordered equality, Counter for equality that ignores order but keeps duplicate counts, set() for unique-value overlap or differences, and a list comprehension when the result must follow an input list’s order.
All examples below use the Python standard library and were verified with Python 3.14.7. The same methods work in supported earlier Python 3 versions unless a project imposes a different compatibility requirement.
| Goal | Recommended method | Order matters | Duplicate counts matter | Element requirement |
|---|---|---|---|---|
| Test exact list equality | left == right |
Yes | Yes | Elements must support equality |
| Test unordered equality | Counter(left) == Counter(right) |
No | Yes | Elements must be hashable |
| Compare unique values | set() operations |
No | No | Elements must be hashable |
| Keep common items in list order | List comprehension plus a membership set | Output order only | Repeats from the scanned list remain | Membership values must be hashable |
| Keep counts in overlap or differences | Counter operations |
No | Yes | Elements must be hashable |
These choices answer different questions rather than competing to be one universally fastest method. Equality returns one Boolean, set and Counter operations build collection-like results, and a comprehension controls the shape and order of a new list. Decide the required semantics before considering performance; changing representations merely to make a comparison faster can also change the answer.
Compare Exact Ordered Lists With ==
Python list equality compares corresponding elements from left to right. Two lists are equal only when they have the same length, equal values at every position, and therefore the same order. This is the clearest choice when a list represents a sequence such as processing steps, ranked results, or ordered events.
"""Verify that list equality considers both values and order."""
first = [1, 2, 3]
same = [1, 2, 3]
reordered = [3, 2, 1]
print(first == same)
print(first == reordered)
True
False
The second comparison is False even though both lists contain the same unique values. Direct equality also works with unhashable elements such as nested lists because it does not build a hash table.
The element comparisons still follow each value’s equality rules. For example, comparing lists of custom objects may invoke those objects’ __eq__ implementations. This method does not recursively report where two nested structures differ; it only returns the final Boolean result.
Compare Unordered Lists While Keeping Duplicate Counts
Use collections.Counter when order should be ignored but each value’s frequency still matters. A Counter maps every hashable item to its count, so two counters are equal only when both lists contain the same values with the same multiplicities.
"""Compare unordered lists with and without duplicate multiplicity."""
from collections import Counter
left = [1, 2, 2, 3]
reordered = [3, 2, 1, 2]
fewer_duplicates = [3, 2, 1]
print(Counter(left) == Counter(reordered))
print(Counter(left) == Counter(fewer_duplicates))
print(set(left) == set(fewer_duplicates))
True
False
True
The last two lines expose an important boundary: Counter detects the missing second 2, whereas a set comparison reports equality because sets discard duplicates. Do not use set(left) == set(right) as a substitute when repeated values have meaning.
The built-in sorted() function offers another duplicate-aware option through sorted(left) == sorted(right), but only when all values in the lists are mutually orderable. It also allocates sorted lists and performs sorting work, so Counter usually expresses unordered frequency equality more directly. Sorting can still be useful when the sorted sequences are needed afterward.
Compare Unique Values and Find Overlap or Differences With set()
Convert lists to sets when only distinct values matter. Set intersection (&) returns values present in both inputs. Difference (-) is directional, while symmetric difference (^) returns values present on only one side.
The following verified example sorts only the displayed set results so that the output is deterministic. The comparison itself does not assign an order to a set.
Set conversion can be attractive for membership-heavy tasks because it creates a lookup structure once, but it is not appropriate when the output must retain position or multiplicity. Also avoid relying on the printed order of a set; explicitly sort only when values are mutually orderable and a stable presentation is needed.
"""Verify unique-value, order-preserving, and multiplicity-aware differences."""
from collections import Counter
left = [1, 2, 2, 3, 4]
right = [2, 3, 3, 5]
left_set = set(left)
right_set = set(right)
print(sorted(left_set & right_set))
print(sorted(left_set - right_set))
print(sorted(right_set - left_set))
right_members = set(right)
print([item for item in left if item in right_members])
left_counts = Counter(left)
right_counts = Counter(right)
print(sorted((left_counts & right_counts).elements()))
print(sorted((left_counts - right_counts).elements()))
print(sorted((right_counts - left_counts).elements()))
[2, 3]
[1, 4]
[5]
[2, 2, 3]
[2, 3]
[1, 2, 4]
[3, 5]
The first three output lines show unique-value overlap and directional differences. If you also need values that occur in exactly one set, use left_set ^ right_set; with these inputs, that produces the unique values 1, 4, and 5 in unspecified order.
Preserve Result Order With a List Comprehension
A set result does not preserve the first list’s order. When output order matters, build a membership set once and scan the list whose order you want to retain. In the preceding example, right_members is created once before the comprehension instead of rebuilding or linearly scanning the second list for every element.
The fourth output line, [2, 2, 3], keeps the order and repeated occurrences from left. This result is intentionally asymmetric: scanning right instead would preserve right’s order and duplicates. If the membership values are unhashable, use direct equality-based membership against the other list, understanding that repeated list scans can cost more for large inputs.
Preserve Multiplicity in Overlaps and Differences With Counter
Set operations answer questions about unique values. Counter operations answer the same kinds of questions while preserving counts:
left_counts & right_countskeeps the minimum positive count for each shared value.left_counts - right_countssubtracts counts and keeps only positive remainders.right_counts - left_countsgives the difference in the other direction..elements()expands the resulting counts back into individual values.
For the verified example, the multiset overlap is [2, 3], not [2, 2, 3]: 2 occurs twice on the left but only once on the right, so the minimum count is one. The directional left remainder is [1, 2, 4], and the right remainder is [3, 5].
Choose this method for inventories, votes, tags with repetitions, or other data where quantity matters. A plain set would silently erase that information.
Counter arithmetic removes zero and negative counts from these multiset results. That behavior is helpful for remaining-item questions, but it is different from ordinary numeric subtraction over every possible key. Inspect the counters directly if an application must retain zero or negative balances.
Handle Unhashable Values and Choose the Correct Method
set() and Counter both require hashable elements. Lists are mutable and unhashable, so nested lists trigger TypeError; direct list equality continues to work:
"""Show the unhashable-item boundary of set and Counter comparisons."""
from collections import Counter
left = [[1], [2]]
right = [[1], [2]]
print(left == right)
for name, operation in (("set", set), ("Counter", Counter)):
try:
operation(left)
except TypeError as error:
print(f"{name}: {error}")
True
set: cannot use 'list' as a set element (unhashable type: 'list')
Counter: unhashable type: 'list'
The exact set diagnostic can vary between Python releases, so treat the exception type and the unhashable-element cause as the stable behavior. If nested sequences can be represented immutably, convert each inner list to a tuple before using a set or Counter; otherwise, keep an equality-based comparison suited to the required result.
In short, choose the representation that matches the data’s meaning: == for ordered sequences, Counter for unordered multisets, set() for unique values, and an order-preserving comprehension for filtered output. Making the order and duplicate rules explicit prevents comparisons that look correct but answer the wrong question.