使用linq拆分列表

Ano*_*nym 9 c#

我有以下代码:

  var e = someList.GetEnumerator();
  var a = new List<Foo>();
  var b = new List<Foo>();
  while(e.MoveNext())  {
     if(CheckCondition(e.Current)) {
         b.Add(e.Current);
         break;
     }
     a.Add(e.Current);
 }

while(e.MoveNext())
  b.Add(e.Current)
Run Code Online (Sandbox Code Playgroud)

这看起来很难看.基本上,遍历列表并将元素添加到一个列表中,直到某些条件启动,然后将其余内容添加到另一个列表中.

有没有更好的方法,例如使用linq?CheckCondition()很昂贵,列表可能很大,所以我宁愿不做任何迭代列表两次的事情.

Tho*_*que 8

这是一个将列表枚举两次的解决方案,但它不会第二次检查条件,所以它应该更快:

var a = someList.TakeWhile(x => !CheckCondition(x)).ToList();
var b = someList.Skip(a.Count).ToList();
Run Code Online (Sandbox Code Playgroud)

如果someList实现IList<T>,每个项目实际上只会被枚举一次,因此不会有任何惩罚.
我认为Skip是针对这种情况进行了优化IList<T>,但显然它不是......但是你可以轻松实现自己Skip使用这种优化的方法(参见Jon Skeet关于此的文章)

如果有TakeUntil方法,它实际上会更优雅......我们可以轻松地创建它:

public static IEnumerable<TSource> TakeUntil<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    foreach(var item in source)
    {
        if (predicate(item))
            break;
        yield return item;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此方法,代码变为:

var a = someList.TakeUntil(CheckCondition).ToList();
var b = someList.Skip(a.Count).ToList();
Run Code Online (Sandbox Code Playgroud)

  • +1:很好,但是我认为*`Skip`在.NET 4中没有你对`IList <T>`的优化.但不确定. (5认同)