Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I extract part of an IEnumerable based on known elements of the collection?

Tags:

c#

linq

I have a collection, specifically an IList<T>. I know two elements within the collection, startElement and endElement.

Is there a LINQ query that will return the enumerable from startElement to endElement, inclusive?

I thought about using sequence.SkipWhile(p=>p!=startElement).TakeWhile(q=>q!=endElement) but that misses out the last element...

like image 389
Tim Long Avatar asked Aug 10 '15 22:08

Tim Long


2 Answers

This doesn't use LINQ, but it's probably the most straightforward/readable approach.

        int startIndex = sequence.IndexOf(startElement), 
            endIndex = sequence.IndexOf(endElement);

        var range = sequence.GetRange(
                         startIndex, 
                         // +1 to account for zero-based indexing
                         1 + endIndex - startIndex
                    );

Note that this is technically less efficient than alternatives, but if you already have an IList in memory, the differences will likely be less than a millisecond which is a small sacrifice to make for readable code.

I'd recommend wrapping the code block with a Stopwatch to test against your specific situation to be sure, however.

like image 64
Colin Avatar answered Sep 22 '22 00:09

Colin


This will be the most efficient, as it doesn't create any unnecessary enumerator objects and only traverses the list one time.

var result = new List<T>();
var inSequence = false;

for (var i = 0; i < list.Length; i++)
{
    var current = list[i];

    if (current == startElement) inSequence = true;
    if (!inSequence) continue;

    result.add(current);
    if (current == endElement) break;
}

This won't handle the case where endElement is missing, but you could do that pretty easily by assigning result = null as the last line of the for loop where i = list.Length - 1

like image 20
Haney Avatar answered Sep 23 '22 00:09

Haney