Why is `in` slow on a list but fast on a set?
x in list compares against each element until it finds one, so it is O(n) — and a miss always costs the full length. x in set computes where the value would be and looks there: O(1). Swapping one for the other is usually a one-character change with a thousandfold effect.
Overview
The two mechanisms
A list has no idea where anything is, so in walks it comparing element by element. Best case one comparison, worst case n, and a value that is absent always costs n.
A set stores values in slots chosen from their hashes. in hashes the value, goes to that slot and compares. The length of the set does not enter into it — see hash tables for the machinery.
Step through it
What to watch
- The list compares one element at a time and stops at the hit.
- A miss checks all of them — the worst case is the common case.
- The set makes one probe regardless of size.
Say this out loud
"`in` on a list is a linear scan, O(n). On a set or dict it's a hash lookup, O(1). If I'm testing membership repeatedly I build a set first - that's O(n) once instead of O(n) every time."