How to get the index of an element in an IEnumerable?
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
IEnumerable<T> does not have a built-in IndexOf method because it represents a forward-only sequence with no concept of position. To find the index of an element, use LINQ's Select to project each element with its index, then filter with FirstOrDefault. Alternatively, write a simple extension method, or convert to a List<T> and use its IndexOf method. Each approach trades off readability, performance, and reusability.
Method 1: LINQ Select with Index
LINQ's Select overload provides the index of each element:
This iterates until the first match is found, then stops. If the element is not found, it returns -1.
Using Tuples (C# 7+)
Method 2: Extension Method
Create a reusable IndexOf extension method for IEnumerable<T>:
Method 3: Convert to List
The simplest approach if you need multiple lookups:
ToList() materializes the entire sequence into memory. This is wasteful if you only need one index lookup, but efficient if you need multiple lookups because List<T>.IndexOf is O(n) per call without re-enumerating the source.
Method 4: Manual Loop
This is the most efficient approach for a single lookup — no allocations beyond the enumerator.
Finding All Indices
With Custom Equality
.NET 9+ Index Operator
Starting in .NET 9, LINQ added Index() which returns (int Index, TSource Item) pairs:
Common Pitfalls
- IEnumerable may be non-repeatable: Some
IEnumerable<T>sources (database queries, network streams, generators) can only be enumerated once. CallingSelect(...).FirstOrDefault(...)and then enumerating again produces different results or throws. Materialize withToList()first if you need multiple passes. - Default tuple has index 0, not -1: Using
FirstOrDefaultwith value tuples returns(default, 0)when no match is found, which looks like index 0. Use nullable types or the anonymous object approach to distinguish "found at 0" from "not found". - O(n) performance: Every approach iterates the sequence element by element. If you need frequent index lookups, convert to a
List<T>or build aDictionary<T, int>for O(1) lookups. - Multiple enumerations: Chaining
.Select().Where().Select()still only enumerates once (LINQ is lazy). But callingIndexOftwice on the sameIEnumerable<T>enumerates it twice. Consider materializing if you need multiple lookups. - Index instability: The index of an element in an
IEnumerable<T>depends on the enumeration order, which may change if the source is modified or if the source does not guarantee order (e.g.,HashSet<T>). Only rely on indices for ordered, stable sources.
Summary
- Use
Select((value, i) => ...)withFirstOrDefaultfor a one-off LINQ-based index lookup - Write an
IndexOfextension method for reusable, clean syntax - Convert to
List<T>and useList.IndexOf()if you need multiple lookups - All approaches are O(n) —
IEnumerable<T>has no concept of position - Be careful with
FirstOrDefaulton value tuples — default index is 0, not -1
Related reading
- How to get the insert ID in JDBC?
- How to get the max of two values in MySQL?
- How to get the mysql table columns data type?
- How to get the next auto-increment id in mysql
- How to get the latest offset from the Kafka topic in Confluent kafka C# library?
- How to get the type of T from a member of a generic class or method
- How to get the nth element of a python list or a default if not available
- How to get the number of days of difference between two dates on MySQL?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.