Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a more efficient LINQ statement to reverse-search for a condition in a List<T>?

Tags:

c#

list

linq

We're trying to write a LINQ statement against a List<T> that searches backwards from the end of that list for a condition, but which stops at a specified 'T' item.

For instance, if the list has 1000 items and the 'limit' item is at position 995 (index 994), then we only want to search the last six items for the test condition. We need this to be as high-performance as possible.

However, to use LINQ, the only way we know is to get the existing index of the 'limit' item, which is expensive, then run a Select with index over the entire source collection, which also is expensive, like this...

// Assume limitItem is of type Foo and sourceList is of type List<Foo> 

var limitIndex = sourceList.IndexOf(limitItem);
var sourceListWithIndex = sourceList.Select( (Foo, Index) => new { Foo, Index } );

var fooWithIndex = sourceListWithIndex
    .LastOrDefault(item =>
        (item.Foo.SomTestValue == true)
        &&
        (item.Index >= limitIndex) );

So is there an easier way to tell Linq 'Stop enumerating if you've checked this item', or will I have to manually do it myself in an index-based loop and not use LINQ at all?

like image 253
Mark A. Donohoe Avatar asked Oct 03 '13 16:10

Mark A. Donohoe


People also ask

Is LINQ inefficient?

LINQ syntax is typically less efficient than a foreach loop. It's good to be aware of any performance tradeoff that might occur when you use LINQ to improve the readability of your code. And if you'd like to measure the performance difference, you can use a tool like BenchmarkDotNet to do so.

What does LINQ where return if not found?

Returns the last element of a sequence, or a default value if no element is found.

What does .select do in C#?

In a query expression, the select clause specifies the type of values that will be produced when the query is executed. The result is based on the evaluation of all the previous clauses and on any expressions in the select clause itself. A query expression must terminate with either a select clause or a group clause.

What is reverse in LINQ C#?

Given a list of city names, we need to reverse the list of cities and this can be done using the reverse() method in LINQ. The Reverse() method reverses the sequence of the elements in the specified list. it is available in both Queryable and Enumerable classes.


1 Answers

You don't need any of that.

sourceList.Reverse()
          .TakeWhile(o => o != limitItem)
          .FirstOrDefault(o => ...);

Thanks to deferred execution (and assuming sourceList implements IList<T>), this will iterate part of the list exactly once.

like image 154
SLaks Avatar answered Oct 16 '22 18:10

SLaks