【问题标题】:How to collapse list of bools into list of ints如何将布尔列表折叠成整数列表
【发布时间】:2015-12-18 20:07:54
【问题描述】:

如果我有一个布尔值列表,如何使用 LINQ 转换成一个整数列表(或任何其他 IEnnumerable<int>),其中每个整数代表每个布尔值字符串的长度?

例如,{true, true, false, false, true, true, true} 将变为 {2, 3},因为 trues 的第一次运行是 2 长,第二次运行是 3 长。还是我必须回到 for 和 foreach 循环?

我对错误值的数量不感兴趣,它们之所以重要只是因为它们分隔了真实值的运行。

所以{true, true, true, false, true, true, true, true, false, false, true, true, true} 会变成{3, 4, 3}

【问题讨论】:

  • for 循环有什么问题?它可能比复杂的 Linq 查询更清晰、更容易理解。 See here 用于 Linq 解决方案
  • 甚至yourBooleanList.ForEach(i => i......);
  • 我会使用 IEnumerable 扩展。
  • 另外,为什么你的例子的结果不是{2, 2, 3}?或者您只是对 true 值的组感兴趣?
  • 请澄清您是否只想计算最大组真假布尔值的问题。

标签: c# linq


【解决方案1】:

类似这样的:

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;
    }
}

然后像这样使用:

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

使用纯LINQ方式(主要取自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());

【讨论】:

  • 是的,纯 LINQ 代码有点可怕——我想我会坚持使用扩展方法
  • 是的,但我添加它只是因为。我会使用第一种方法,它更快且更具可读性。
  • 人们真的需要停止推荐 LINQ。除了在每个可能的实现中它都非常缓慢的事实之外,它还创建了令人费解且难以理解的呕吐-说话-代码。对于你最终离开时坐在你座位上的人来说,这绝对是一场噩梦。
  • @Krythic LINQ 有一个很有价值的地方,但是像所有工具一样,如果你尝试将它用于所有事情,那么用螺丝刀敲钉子看起来很愚蠢。另一方面,说你永远不应该使用它可能更糟糕。
  • @Krythic 看看我的 LINQ 答案,有一种方法可以以非常简单的方式实现它。只有一个 Aggregate 和两个 Func 的 :)。当然,可能有太多 LINQ 或可怕的 LINQ,但在大型项目中,如果“合理”完成,它可以简化对必须解决的问题的思考。另一方面,如果 LINQ 只在顶层添加下一层复杂性,那么它就会尖叫 BAD DESIGN :)。
【解决方案2】:

没有糟糕的 LINQ,只有糟糕的想法:)。 它可以用 LINQ 很好地完成,而且仍然知道它的作用。

好吧,我希望如此:)。

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}

【讨论】:

    【解决方案3】:

    前段时间,我制作了一个通用版本,用于查找连续元素。 它适用于任何实现 IComparable 的东西,并且可以选择感兴趣的元素是什么。

    只是一个思考的食物:)。

    public
    static
    class IEnumerableExtensions
    {
        public
        static
        IEnumerable<int> CountConsecutiveElements<TElement>(this IEnumerable<TElement> ie,
                                                                 TElement consecutive_element)
            where TElement: IComparable<TElement>
        {
            using(var en = ie.GetEnumerator())
            {
                int i = 0;
                while (en.MoveNext())
                {
                    if (en.Current.CompareTo(consecutive_element) == 0) i++;
                    else if (i > 0)
                    {
                        yield return i;
                        i = 0;
                    }
                }
                if (i > 0) yield return i;
            }
        }
    }
    

    然后使用就很简单了:

    List<bool> lst = new List<bool>() { true, true, true, false, true, true,
                                        true, true, false, false, true, true,
                                        true };
    
    //var rslt = lst.CountConsecutiveElements(true).ToList();
    //there is no need for .ToList()
    
    var rslt = lst.CountConsecutiveElements(true);
    //{3, 4, 3}
    

    【讨论】:

      猜你喜欢
      • 2021-08-20
      • 2016-01-02
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      • 1970-01-01
      • 2010-11-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多