Reputation: 41
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
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
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