Finding first index of element that matches a condition using LINQ
var item = list.Where(t => somecondition);
I would love to be able to find out the index of the element that was returned, in fact, in my case all I want is an index, so that I can .Skip() into the list by that much.
Is there a way to do this in an IEnumerable? I'd hate to use a List<T>
for this, but that does have a FindIndex()
method
If you really just need the first index then count the ones that don't match:
var index = list.TakeWhile(t => !someCondition).Count()
Sure, it's pretty easy:
var index = list.Select((value, index) => new { value, index = index + 1 })
.Where(pair => SomeCondition(pair.value))
.Select(pair => pair.index)
.FirstOrDefault() - 1;
That will return the index if it finds anything matching, or -1 otherwise. The +1 and -1 is to get the behaviour for the case where there are no matches. If you knew that there would always be a match, it would be simpler:
var index = list.Select((value, index) => new { value, index })
.Where(pair => SomeCondition(pair.value))
.Select(pair => pair.index)
.FirstOrDefault();
If you're happy to get the rest of the list from that point onwards, SkipWhile
is definitely your friend, as mentioned by Chris. If want the rest of the list and the original index, that's easy too:
var query = list.Select((value, index) => new { value, index })
.SkipWhile(pair => !SomeCondition(pair.value))
That will give you a sequence of { value, index }
pairs from the first value matching SomeCondition
.
I'd need more context, but if you're just getting an index so that you can call .Skip
, I would recommend taking a look at .SkipWhile
.
If you do really need the index, I'd suggest writing your own .IndexOf
extension method.
Ofcourse its possible using IEnumerable...
public static class EnumerableExtension
{
public static int FirstIndexMatch<TItem>(this IEnumerable<TItem> items, Func<TItem,bool> matchCondition)
{
var index = 0;
foreach (var item in items)
{
if(matchCondition.Invoke(item))
{
return index;
}
index++;
}
return -1;
}
}
You can project the list items with their indexes first:
var item = list.Select((item, index) => new { Item = item, Index = index })
.Where(pair => SomeCondition(pair.Item))
.Select(result => result.Index);