【问题标题】:Is there a "split list" method in c#?c# 中是否有“拆分列表”方法?
【发布时间】:2013-07-18 02:12:15
【问题描述】:

在 C# 中,调用 .Split 方法会根据某个字符或字符串将字符串拆分为字符串数组。

列表或数组是否有等效的方法?

例如:

var foo = new List<int>() { 1, 2, 3, 0, 4, 5, 0, 6 };
var output = Split(foo, 0);
// produces { { 1, 2, 3 }, { 4, 5 }, { 6 } }

这就是我目前所拥有的——是否有更简洁或更雄辩的方式来完成相同的任务?

IEnumerable<IEnumerable<T>> Split<T>(IEnumerable<T> list, T divider)
{
    var output = new List<List<T>>();
    var temp = new List<T>();
    foreach ( var item in list )
    {
        if (item.Equals(divider))
        {
            output.Add(temp);
            temp = new List<T>();
        }
        else
        {
            temp.Add(item);
        }
    }

    output.Add(temp);
    return output;
}

编辑:

我突然想到,我的版本只会按单个元素拆分列表,而 string.Split 可以使用单个字符或任意字符串进行拆分。

为了完整起见,最好的实现方式是什么?

【问题讨论】:

  • 你也许可以用 IndexOf 做点什么,虽然我不确定它如何比较一般的平等......
  • 在您的编辑中 - 虽然使用单个分隔符很简单,什么是“好/更好”的代码,但匹配序列并非如此:您需要在匹配期间正确处理未命中( aabbababab 上拆分需要某种形式的重新访问,首先要返回 b 以在多种方法上进行不同的权衡。还有许多不同的字符串匹配算法(这正是您在编辑中想要的),它们针对不同的标准进行了优化。所以编辑并不是真正可以回答的(在“最好”的意义上)。
  • Group by element in Linq 的可能重复项

标签: c# algorithm linq list


【解决方案1】:

没有内置的等价物,但会是惰性求值的

IEnumerable<IEnumerable<T>> Split<T>(IEnumerable<T> list, T divider)
{
    var temp = new List<T>();
    foreach (var item in list)
    {
        if (!item.Equals(divider))
        {
            temp.Add(item);
        }
        else
        {
            yield return temp;
            temp = new List<T>();
        }
    }

    if(temp.Count>0) yield return temp;
}

【讨论】:

    【解决方案2】:

    不,框架中没有特殊的现有方法来拆分序列。

    你的代码是合理的。

    改进/改变的路线:

    • 您可以使用yield return 而不是添加到output 以获得一些惰性评估。
    • 使用更有趣的代码,您也可以使内部列表变得惰性(如果传入的序列未绑定/段太长,这可能很重要)。
    • 如果你想炫耀单个语句代码,你可以使用Aggregate...

    【讨论】:

      【解决方案3】:

      不知道任何内置函数。但是,我会考虑这样做:

      public static IEnumerable<List<int>> Split(List<int> list, int delimiter)
      {
          var start = 0;
          foreach (var end in list.FindAll(x => x == delimiter).Select(splitter => list.IndexOf(splitter, start)))
          {
              yield return list.GetRange(start, end - start);
      
              start = end + 1;
          }
      
          if (start <= list.Count)
          {
              yield return list.GetRange(start, list.Count - start);
          }
      }
      

      【讨论】:

      • 不确定这是否真的是对 Op 方法的改进……它可能更具可读性,但它还需要 (?) 对输入进行多次传递。
      • 如果listIEnumerable&lt;T&gt; 而不是List&lt;T&gt; 将不起作用(因为GetRange
      猜你喜欢
      • 2021-12-05
      • 1970-01-01
      • 2014-05-30
      • 2021-11-24
      • 2017-07-18
      • 1970-01-01
      • 2017-09-13
      • 1970-01-01
      • 2021-07-26
      相关资源
      最近更新 更多