Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to collapse list of bools into list of ints

Tags:

c#

linq

If I have a list of booleans, how do I convert into into a list (or any other IEnnumerable<int>) of integers where each integer represents the length of each string of booleans using LINQ?

For example {true, true, false, false, true, true, true} would become {2, 3} as the first run of trues is 2 long, and the second is 3 long. Or must I go back to for and foreach loops?

I am not interested in the number of false values, they are only important because they separate runs of true values.

So {true, true, true, false, true, true, true, true, false, false, true, true, true} would become {3, 4, 3}

like image 697
euanjt Avatar asked Feb 08 '23 06:02

euanjt


2 Answers

Something like this:

public static class IEnumerableExt
{
    public static IEnumerable<int> ConsecutiveTrues(this IEnumerable<bool> bools)
    {
      var flag=false;
      int count=0;
      foreach(var b in bools)
      {
        if (b)
        {
          count++;
        } else if (flag)
        {
            yield return count;
            count=0;
        }
        flag=b;
      }
      if (flag)
        yield return count;
    }
}

then used like:

void Main()
{
  var bools=new bool[]{true, true, false, false, true, true, true};
  var results=bools.ConsecutiveTrues();
}

Using a pure LINQ way (taken mostly from https://stackoverflow.com/a/27574266/856353):

var str = new bool[]{true, true, true, false, true, true, true, true, false, false, true, true, true};

// Retain a horrid mutable sequence which tracks consecutive characters
var sequence = 0;
var grps = str
  .Zip((str.Concat(new bool[]{str.Last()})).Skip(1),
     (prev, current) => new { prev, current })
  .GroupBy(p => new { 
      Ch = p.prev, 
      Sequence = p.current == p.prev
      ? sequence 
      : sequence++})
  .Where(l=>l.Key.Ch==true)
  .Select(l=>l.Count());
like image 133
Robert McKee Avatar answered Feb 15 '23 11:02

Robert McKee


There is no bad LINQ, just bad ideas:). It can be done with LINQ pretty nicely and still, one knows what it does.

Well, I hope so:).

List<bool> lst = new List<bool>() { true, true, true, false, true, true,
                                    true, true, false, false, true, true,
                                    true };

var bb =
lst
.Aggregate(new List<int>(), (acc, element) =>
{
    if (element == true && acc.Count < 1) acc.Add(1);
    else if (element == true && acc.Count > 0) acc[acc.Count - 1] = acc[acc.Count - 1]++;
    else if(acc.Count > 0 && acc[acc.Count - 1] > 0) acc.Add(0);
    return acc;
}, acc =>
{
    if (acc.Count > 0 && acc[acc.Count - 1] == 0)
    {
        acc.RemoveAt(acc.Count - 1);
    }
    return acc;
});
//{3, 4, 3}
like image 27
ipavlu Avatar answered Feb 15 '23 09:02

ipavlu