Vandrer
Vandrer

Reputation: 41

Cut list using LINQ

I have a List where I want to cut all the false values before the first true value and all the false values after the last true value.

I know I can do this with a loop from each direction. I am just curious if there is an easier way to do this using LINQ.

Upvotes: 0

Views: 1427

Answers (2)

Audric de Schaetzen
Audric de Schaetzen

Reputation: 124

Say your input is as follows:

var values= new List<bool>()
        { false, false,
          true, false, false ,true, false, true, //this is the part you want
          false, false, false};

The easiest way would of course be to simply get the indexes of the first and last occurrence of a true value, and get the contents between these two indexes.

if (values.Contains(true)) //check if there is actually at least one true.
{
    var firstIndex = values.IndexOf(true);
    var lastIndex = values.LastIndexOf(true);
    var count = lastIndex - firstIndex + 1; //include last index
    var result = values.GetRange(firstIndex, count);
}

If you really want to use LINQ, but would rather not worry about lookaheads, you can use SkipWhile() to skip everything up to the first true, then reverse the list, and SkipWhile() again up to the first true.

if (values.Contains(true)) //check if there is actually at least one true.
{
    var result = values.SkipWhile(x => !x).Reverse().SkipWhile(x => !x);
};

Upvotes: 1

CodeCaster
CodeCaster

Reputation: 151674

So given this input:

var input = new List<bool>
{
    false,
    false,
    true, // first true
    true,
    false,
    true, // last true
    false
};

You want true, true, false, true, right?

The trivial way would be to use (Last)IndexOf:

var firstTrue = input.IndexOf(true);
var lastTrue = input.LastIndexOf(true);

var indexed = input.Skip(firstTrue).Take(lastTrue - firstTrue + 1).ToList();

This will worst-case iterate the list twice, once for IndexOf call, and needs error checking (what if no true are in the input?).

If you insist on LINQ, it becomes harder, as functional prorgamming works on single items of a set as a time, not considering the set as a whole. So while evaluating for each list item whether they're to be included, you need to keep scanning forward in the list (as to not let the first false stop the search):

var output = input.SkipWhile(t => t == false)
                  .TakeWhile((b, i) => b == true || input.Skip(i + 2).Contains(true));

Upvotes: 2

Related Questions