How to Compare Two Arrays in Python
Use sets for membership checks, loops for positional diffs, and a visual browser diff when the data stops being simple.
Last updated
Python gives you several ways to compare lists, but the right approach depends on what you mean by compare. Sometimes you only care about missing values. Sometimes order matters. Sometimes the list contains dicts and nested structures where a set operation stops being useful.
1. Compare membership with set difference
If you only care about which values appear in one list but not the other, convert both lists to sets and compare the membership results.
left = ['flask', 'django', 'requests', 'numpy']
right = ['flask', 'fastapi', 'requests', 'pandas']
removed = set(left) - set(right)
added = set(right) - set(left)This is fast and clear, but it drops ordering and duplicates. If ['a', 'a', 'b'] matters to you, a set is the wrong tool.
2. Compare by position when order matters
Use a loop when index position is part of the meaning of the data. This is common when you are checking pipeline output, sorted reports, or arrays that are expected to stay stable between runs.
for i in range(max(len(left), len(right))):
before = left[i] if i < len(left) else '(missing)'
after = right[i] if i < len(right) else '(missing)'
if before != after:
print(i, before, after)3. Nested lists and dicts need a deeper comparison
Once the list contains dicts, nested arrays, or mixed types, a manual loop becomes noisy. You can serialize the data or use a library like DeepDiff, but for quick inspection a browser-based visual diff is faster because it shows every added, removed, and modified path side by side.
4. Duplicates need Counter, not set
A set answers "does this value appear at all", which silently collapses duplicates. If ['a', 'a', 'b'] and ['a', 'b'] should be different, set difference will tell you they are the same. collections.Counter is the multiset equivalent and keeps the counts.
from collections import Counter
left = ['flask', 'flask', 'requests']
right = ['flask', 'requests']
set(left) - set(right) # set() -> looks identical
Counter(left) - Counter(right) # Counter({'flask': 1}) -> one extra
Counter subtraction drops zero and negative counts, so run it in both directions to get added and removed. This matters most for data that came from a database or a log: duplicate rows are usually the bug you are looking for, and a set is the one tool guaranteed to hide them.
5. Lists of dicts: key them first
Dicts are unhashable, so set(list_of_dicts) raises TypeError: unhashable type: 'dict'. The fix is not to serialise every dict to a string — that makes key order significant and produces false differences. Build an index on whatever field is the real identity instead, then compare the keys and the values separately.
left_by_id = {row['id']: row for row in left}
right_by_id = {row['id']: row for row in right}
added = right_by_id.keys() - left_by_id.keys()
removed = left_by_id.keys() - right_by_id.keys()
changed = {i for i in left_by_id.keys() & right_by_id.keys()
if left_by_id[i] != right_by_id[i]}
This separates the three questions that actually matter — what appeared, what disappeared, and what changed in place — and it stays O(n) rather than degrading into a nested scan.
6. Two comparisons that quietly return the wrong answer
Float equality is the first. 0.1 + 0.2 == 0.3 is False, so any list of computed floats will show phantom differences. Compare with math.isclose() or round to a fixed precision before diffing.
Type strictness is the second. [1, 2, 3] == (1, 2, 3) is False because a list is not a tuple, and 1 == 1.0 is True but '1' == 1 is not. Data arriving from CSV, environment variables, or JSON often carries numbers as strings, so normalise types before comparing rather than after seeing a diff you do not believe.
Sorting is the third trap: sorted() on a mixed-type list raises TypeError in Python 3, so "just sort both sides" fails on exactly the messy data that most needs comparing.
Watch the cost when lists get large
Set and dict based comparison is linear, so it stays fast at any size you are likely to paste into a browser. Order-insensitive comparison that scores every pair for similarity is quadratic — measured at O(n2.077) in this site's own engine, where 4,000 elements take 89 seconds while an ordered pass over 50,000 takes under 6 milliseconds.
The practical rule follows directly: if order does not matter and the lists are large, sort or key them first and then compare positionally. That converts a quadratic problem into an O(n log n) sort plus a linear pass, which is the same reason left_by_id above beats a nested loop.
When to switch to ArrayDiff
Use Python List Diff when you need a full visual explanation instead of a boolean or a pair of sets. It is especially useful for ETL debugging, comparing exported DataFrame rows, and reviewing JSON-serializable Python objects from test fixtures.
If your Python data is already JSON-shaped and you care about keys inside dicts, go directly to Python JSON Diff or the broader Array Comparison Tools hub.
Frequently asked questions
What is the fastest way to compare two lists in Python?
For membership only, set(a) - set(b) is O(n) and hard to beat. For lists of dicts, build a dict keyed on an identity field and compare keys — also O(n). Avoid nested loops (for x in a: if x in b), which are O(n²) because the inner in scans the whole list each time.
Why does set difference say my lists are identical when they are not?
Sets discard both order and duplicates. ['a', 'a', 'b'] and ['b', 'a'] produce the same set. Use collections.Counter if duplicates matter, or compare by index if order matters.
How do I compare a list of dictionaries?
Do not put them in a set — dicts are unhashable and it raises TypeError. Index both lists by a stable identity field into dicts, then take the key differences for added and removed and compare values for the shared keys.
Why do my float comparisons show differences that should not exist?
Binary floating point cannot represent most decimals exactly, so 0.1 + 0.2 is 0.30000000000000004. Use math.isclose(a, b) or round both sides to a fixed precision before comparing.
Should I use DeepDiff instead?
DeepDiff is a good fit when you need a structured diff object inside a program — in tests or a pipeline. For a one-off comparison a human will read, a dependency is overkill; the recipes above or a visual diff get you there faster.