Efficiently finding duplicates in a list
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
Finding duplicates efficiently depends on what you actually need: whether you want to know if any duplicate exists, list the repeated values, count frequencies, or preserve the original order of repeated items. The naive nested-loop solution works, but it is quadratic and quickly becomes the wrong choice on real data. In Python, hash-based approaches using set or Counter are usually the right starting point.
Fastest General Check: Use a set
If you only need to know whether duplicates exist, compare the list length to the size of a set built from it.
This is typically O(n) average time because set membership and insertion are hash-based.
The tradeoff is that this only works for hashable values such as numbers, strings, and tuples of hashable elements.
Get the Duplicate Values
If you want the repeated elements themselves, track what you have seen and what has repeated.
This returns the duplicated values once each. It does not preserve the order in which duplicates first appeared.
Preserve Encounter Order
If output order matters, keep a list for duplicates and a set to avoid appending the same duplicate more than once.
This pattern is helpful in validation messages where you want deterministic, human-readable output.
Count Frequency with Counter
If you need counts, collections.Counter is usually the cleanest solution.
This is often the best answer for data-cleaning tasks because it tells you not only what repeated, but how often.
Sorting-Based Alternative
If the data is not hashable or you want a solution with lower auxiliary memory in some contexts, sort first and compare adjacent elements.
This is O(n log n) due to sorting. It can be reasonable when hashing is unavailable or when sorted output is desirable anyway.
Unhashable Items Such as Lists or Dicts
If the list contains unhashable items, direct set or Counter use will fail.
For example:
You can convert list elements to tuples if that preserves the meaning you need:
For dictionaries or more complex nested objects, you may need a custom normalization strategy.
Streaming Large Inputs
If the data arrives as a stream and you cannot store everything, a seen-set approach still works for “first duplicate encountered” style detection:
This lets you short-circuit early instead of processing the entire dataset.
When the Naive Approach Is Still Fine
For tiny lists in one-off scripts, a nested loop or repeated count() call may be acceptable. The point is not that every duplicate search needs advanced optimization. The point is that once input size grows, quadratic work becomes avoidable and expensive.
Common Pitfalls
The biggest mistake is using nested loops on large lists when a hash-based approach would be linear on average. Another is forgetting that sets discard order, which may matter if you need deterministic duplicate reporting. Developers also often assume every element is hashable and then hit errors with lists or dictionaries. Finally, Counter is excellent for counts, but it is more work than necessary if all you need is a quick yes or no duplicate check.
Summary
- Use
len(values) != len(set(values))for the fastest simple duplicate-existence check. - Use a seen-set pattern to collect duplicate values efficiently.
- Use
Counterwhen frequency counts matter. - Use sorting if hashing is unavailable or sorted duplicate output is useful.
- Normalize unhashable items first if you need hash-based duplicate detection.
Related reading
- Efficiently finding the largest surrounding square in 2D grid
- Efficiently getting all divisors of a given number
- Efficiently implementing erode/dilate
- Efficiently randomly shuffling the bits of a sequence of words
- Efficiently selecting a set of random elements from a linked list
- Ehcache - using a ListInteger as the cache value
- Efficiently grab gradients from TensorFlow?
- Efficiently querying one string against multiple regexes

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.