python
list-comparison
duplicate-question
programming
code-matching

How can I compare two lists in python and return matches

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Comparing two Python lists is straightforward when you only need unique overlaps, but it gets more nuanced when duplicates matter. The right solution depends on whether you want set style matching or count-aware matching. Choosing the correct strategy prevents subtle logic bugs.

Unique Matches with Set Intersection

If your goal is to find values that appear in both lists at least once, convert lists to sets and intersect them. This is concise and usually fast for large collections.

python
1list_a = [1, 2, 2, 3, 5, 8]
2list_b = [2, 2, 4, 5, 9]
3
4unique_matches = sorted(set(list_a) & set(list_b))
5print(unique_matches)  # [2, 5]

This approach removes duplicates by design. It is ideal for feature flags, IDs, or tags where only presence matters.

Duplicate-Aware Matches with Counter

When duplicates are meaningful, use collections.Counter. You can compute the minimum count for each value and reconstruct the matched list.

python
1from collections import Counter
2
3list_a = [1, 2, 2, 3, 5, 8]
4list_b = [2, 2, 2, 4, 5, 9]
5
6counts_a = Counter(list_a)
7counts_b = Counter(list_b)
8
9matched = []
10for value in counts_a.keys() & counts_b.keys():
11    repeat = min(counts_a[value], counts_b[value])
12    matched.extend([value] * repeat)
13
14print(sorted(matched))  # [2, 2, 5]

This preserves duplicate semantics and is usually clearer than nested loops.

Building a Reusable Utility Function

A utility function makes your intent explicit and gives you one place to test behavior.

python
1from collections import Counter
2from typing import Iterable, List, TypeVar
3
4T = TypeVar("T")
5
6
7def intersect_lists(left: Iterable[T], right: Iterable[T], keep_duplicates: bool = False) -> List[T]:
8    if not keep_duplicates:
9        return list(set(left) & set(right))
10
11    c_left = Counter(left)
12    c_right = Counter(right)
13    result: List[T] = []
14
15    for value in c_left.keys() & c_right.keys():
16        result.extend([value] * min(c_left[value], c_right[value]))
17
18    return result
19
20
21if __name__ == "__main__":
22    a = ["apple", "banana", "banana", "pear"]
23    b = ["banana", "banana", "banana", "kiwi"]
24
25    print(sorted(intersect_lists(a, b, keep_duplicates=False)))
26    print(sorted(intersect_lists(a, b, keep_duplicates=True)))

With a function like this, calling code immediately communicates whether duplicates are required.

Preserve Input Order When Needed

Set and counter based solutions are excellent for correctness and speed, but they do not guarantee that output order matches original data. In reporting pipelines and UI workflows, preserving first-seen order is often required.

You can build an order-preserving matcher with a counter and a single pass over the left list. This keeps duplicates, respects order, and still avoids nested loops.

python
1from collections import Counter
2
3
4def ordered_intersection(left, right):
5    right_counts = Counter(right)
6    out = []
7
8    for value in left:
9        if right_counts[value] > 0:
10            out.append(value)
11            right_counts[value] -= 1
12
13    return out
14
15
16a = ["b", "a", "b", "c", "a"]
17b = ["a", "b", "b", "b"]
18print(ordered_intersection(a, b))  # ['b', 'a', 'b']

The result reflects the sequence from left, which is useful when that sequence has meaning such as event order, user entry order, or priority ranking.

Quick Validation Tests

Before shipping list comparison logic, add a few direct tests for edge cases. Empty input, mixed duplicates, and non-overlapping lists are common sources of incorrect assumptions.

python
assert intersect_lists([], [], keep_duplicates=True) == []
assert sorted(intersect_lists([1, 1], [1], keep_duplicates=True)) == [1]
assert intersect_lists([1, 2], [3, 4], keep_duplicates=False) == []

These checks are small, but they lock in behavior and prevent accidental regressions when the helper evolves.

Common Pitfalls

  • Using set intersection when duplicate counts matter. This silently drops repeated values.
  • Using nested loops for large lists. Time complexity can become expensive quickly.
  • Comparing values with mixed types, such as string "2" and integer 2, and expecting them to match.
  • Forgetting order guarantees. Set-based operations do not preserve original list order.

Summary

  • Use set intersection for unique overlap.
  • Use Counter when duplicates should be preserved.
  • Wrap logic in a helper to keep behavior explicit and testable.
  • Confirm ordering and type assumptions before relying on the result.

Course illustration
Course illustration

All Rights Reserved.