HashSet vs. List: Dramatic Performance Gains in Large Collection Lookups
November 2, 2026
Practical guidance is to convert the collection to a set once (for example, var allowedSet = allowed.ToHashSet()) and then perform Contains checks on the set inside the loop, ensuring the change is beneficial for real-world data sizes.
In performance discussions, HashSet is generally preferred for sizable lookup collections because List.Contains incurs significant cost for many lookups, though there is a caveat that for very small collections or few lookups a List may be faster.
The article notes that the performance bug often lies in the surrounding loop rather than in Contains itself, underscoring the importance of profiling with realistic data sizes.
As datasets grow, Contains on a List scales poorly (O(n × m)), while a HashSet offers near O(1) average-case lookups due to hashing and bucket checks, making it the better choice for large collections.
To measure comparisons during lookups, the author wraps SKUs in a struct that increments a counter on each Equals call, enabling precise tracking of how many comparisons are performed.
A common pitfall is checking membership with List.Contains inside a loop, which can lead to O(n × m) work and hundreds of millions of comparisons for large inputs.
In a test with an allowlist of 5,000 SKUs and 100,000 incoming orders, about half of SKUs appear; the list approach yields 375,031,117 comparisons versus only 49,960 with a hash set, a roughly 7,500-fold reduction in comparisons and about 733× faster in time.
The study compares two approaches—List<Sku> with Contains and HashSet<Sku> with Contains—showing that the set approach dramatically reduces both comparisons and execution time.
Summary based on 1 source
Get a daily email with more Tech stories
Source

DEV Community • Nov 2, 2026
One Contains Call, 375 Million Comparisons