Finding an item in a List using C
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Searching inside List<T> is one of the most frequent operations in C# business code. The best method depends on whether you need a boolean check, an item, an index, or many matches. This guide compares practical options and shows how to choose for correctness and performance.
Choosing the Right Search API
List<T> offers several built-in methods, each aimed at a specific use case:
Containsfor simple equality checks.Findto return first match by predicate.FindIndexfor position lookup.FindAllfor multiple matches.
Using the right method makes code easier to read and avoids unnecessary allocations.
Searching Objects with Predicates
For object lists, define clear predicates and consider null safety.
Keep predicates small and domain-oriented. If predicate logic grows, extract it into a named method for readability and testability.
LINQ Options and Tradeoffs
LINQ methods like FirstOrDefault, SingleOrDefault, and Where are expressive and often preferred in service code.
Use SingleOrDefault only when data integrity requires exactly one match. It throws if more than one item matches, which can be useful but should be intentional.
LINQ readability is strong, but in very hot loops direct List<T> methods may allocate less and run faster.
Performance Considerations at Scale
List<T> search is linear time, so repeated lookups on large collections can become expensive. If you perform frequent key-based lookups, move to dictionary-based indexing.
A dictionary gives near constant-time key lookup and is usually better for repeated access by unique identifier.
Defensive Search Patterns
In APIs and background jobs, missing items are normal outcomes. Avoid throwing exceptions for expected misses.
This keeps control flow predictable and avoids noisy exception logs.
Search Strategy in Request Pipelines
In web APIs, repeated list scans inside each request handler can become a hidden latency cost. If the collection changes rarely, build a lookup index once and refresh it only when source data changes. This pattern reduces per-request work and makes performance more predictable under load.
When data mutates frequently, measure before optimizing. For small lists, linear search may still be simpler and fast enough. Profile with realistic traffic rather than microbenchmarks alone.
Common Pitfalls
A common mistake is using Find and then dereferencing without null checks. If no item matches, the result is null for reference types.
Another issue is confusing Find with Where. Find returns one item, while Where returns an enumerable sequence.
Developers also overuse LINQ inside nested loops, creating avoidable allocations and repeated scans. Pre-indexing often removes the bottleneck.
Finally, equality semantics matter. Contains relies on equality implementation. For custom types, ensure Equals and GetHashCode behavior matches business expectations.
Summary
- Pick search methods based on required output: bool, item, index, or collection.
- Use predicates for object searches and keep them readable.
- Prefer dictionary indexing for frequent key-based lookups.
- Handle not-found cases as normal control flow.
- Validate equality behavior when using
Containswith custom types.

