How to get item from IEnumerable collection using its index in C#?

Viewed 25047

I have IEnumerable list of customerList and index. Now I want to get item of IEnumerable based on index.

For example, if index = 3, it should provide me 3rd item of the IEnumerable .

Please guide.

IEnumerable<Customer> customerList = new Customer[] 
{ 
     new Customer { Name = "test1", Id = 999 }, 
     new Customer { Name = "test2", Id = 915 }, 
     new Customer { Name = "test8", Id = 986 },
     new Customer { Name = "test9", Id = 988 },
     new Customer { Name = "test4", Id = 997 },
     new Customer { Name = "test5", Id = 920 },
};

int currentIndex = 3;   //want to get object Name = "test8", Id = 986
4 Answers

For example, if index = 3, it should provide me 3rd item of the IEnumerable

You know that indexes are zero based in .NET? However, you can use ElementAt:

Customer c = customerList.ElementAt(currentIndex); // 4th

Use ElementAtOrDefault to prevent an exception if there are not enough items, then you get null:

Customer c = customerList.ElementAtOrDefault(currentIndex); // 4th or null

These methods are optimized in a way that they use the IList<T> indexer. So in your example there is actually an Customer[] which implements that interface, hence it will use the indexer.

If the sequence does not implement IList<T> it will be enumerated to find the item at this index.

Don't use IEnumerable if you want index-based access. Use IList instead :

IList<Customer> customerList = new Customer[] 
{ 
 new Customer { Name = "test1", Id = 999 }, 
 new Customer { Name = "test2", Id = 915 }, 
 new Customer { Name = "test8", Id = 986 },
 new Customer { Name = "test9", Id = 988 },
 new Customer { Name = "test4", Id = 997 },
 new Customer { Name = "test5", Id = 920 },
};

With IEnumerable, the only option is to use the ElementAt() extension method.

IEnumerable<T> guarantees only that a collection can be enumerated. It makes no other promises about accessing elements. ElementAt allows access to a specific element by enumerating that collection one item at a time until the required element is reached. That can be expensive.

Luckily, ElementAt checks to see whether the argument is an IList and uses index-based access if possible.

That doesn't mean you should use IEnumerable<T> though. It will confuse maintainers (including you) that don't know what the actual instance behind the variable is. It will also cause performance issues if something that isn't an IList is ever assigned to that variable

This can be achieved using ElementAt method.

If your IEnumerable is not a materialized collection, but a generated sequence, calling ElementAt method multiple times will cause the sequence to be generated multiple times. This is usually not desired, as it unnecessarily consumes resources.

Some of the answers above suggest using IList instead of IEnumerable. Yes, definitely it'll make accessing by index less cumbersome, but using IList has a nasty side effect it makes the collection mutable. I'd use IReadOnlyList instead.

IReadOnlyList<Customer> customerList = new Customer[]
{
    new Customer { Name = "test1", Id = 999 },
    new Customer { Name = "test2", Id = 915 },
    new Customer { Name = "test8", Id = 986 },
    new Customer { Name = "test9", Id = 988 },
    new Customer { Name = "test4", Id = 997 },
    new Customer { Name = "test5", Id = 920 },
};

int currentIndex = 3;   //want to get object Name = "test8", Id = 986

var result = customerList[currentIndex];
customerList.Add(new Customer()); // doesn't compile
customerList[currentIndex] = new Customer(); // doesn't compile

IEnumerable is a 'streaming' data type, so think of it like a stream instead of an array.

var yourCustomer = customerList.Skip(2).First()

However if you wanted a more array like syntax IList may be a better abstraction for your use case.

Related