Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用linq拆分列表_C# - Fatal编程技术网

C# 使用linq拆分列表

C# 使用linq拆分列表,c#,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); } w

我有以下代码:

  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)
var e=someList.GetEnumerator();
var a=新列表();
var b=新列表();
while(如MoveNext()){
如果(检查条件(e.电流)){
b、 加上(e.Current);
打破
}
a、 加上(e.Current);
}
while(如MoveNext())
b、 添加(如当前)
这看起来很难看。基本上,遍历一个列表并将元素添加到一个列表中,直到出现某种条件,然后将其余元素添加到另一个列表中


是否有更好的方法,例如使用linq?CheckCondition()非常昂贵,而且列表可能非常庞大,因此我不想做任何重复列表两次的事情。

我个人认为这里不需要LINQ

我会这样做:

bool conditionHit = false;

foreach (var item in someList)
{
    if (!conditionHit)
        conditionHit = CheckCondition(item);

    var listToBeAdded = conditionHit ? b : a;
    listToBeAdded.Add(item);
}

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

var a = someList.TakeWhile(x => !CheckCondition(x)).ToList();
var b = someList.Skip(a.Count).ToList();
如果
someList
实现了
IList
,每个项目实际上只会被枚举一次,因此不会有任何惩罚。
我以为
Skip
针对
IList
的情况进行了优化,但显然不是。。。但是,您可以轻松实现自己的
Skip
方法,该方法使用此优化(请参阅关于此)

如果有一个
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;
    }
}

这将不止一次地检查第一个列表中的项目,但仅在第一次通过
CheckCondition
调用:

var a = someList.TakeWhile(e => !CheckCondition(e));
var b = someList.Skip(a.Count());

如果
someList
是一个具体的列表,则只需通过每个元素一次:

var a = someList.TakeWhile(x => !CheckCondition(x)).ToList();
var b = someList.GetRange(a.Count, someList.Count - a.Count);
我不想改变,但这里有一个小小的简化

var listToBeAdded = a;
foreach (var item in someList)
{
    if (listToBeAdded == a && CheckCondition(item))
        listToBeAdded = b;

    listToBeAdded.Add(item);
}
尝试一下(不要重复使用Linq的内置方法(以倒带迭代器而闻名)),只需重复使用OP的逻辑(我相信这是有效的,它不会在列表的下半部分重新计算条件),并将其打包到一个整洁的扩展方法和元组中:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;



namespace Craft
{
    class Act
    {
        static void Main(string[] args)
        {

            var a = new List<string>
                { "I", "Love", "You", "More", "Today", "Than", "Yesterday" };

            var tx = a.SplitByCondition(s => s == "More");

            foreach (var s in tx.Item1)
                Console.WriteLine("First Half : {0}", s);

            foreach (var s in tx.Item2)
                Console.WriteLine("Second Half : {0}", s);

            Console.ReadLine();                    
        }

    }//Act

    public static class Helper
    {

        public static Tuple<List<T>, List<T>> SplitByCondition<T>
            (this IEnumerable<T> t, Func<T, bool> terminator)
        {


            var tx = new Tuple<List<T>, List<T>>
                          (new List<T>(), new List<T>()); 

            var iter = t.GetEnumerator();

            while (iter.MoveNext())
            {
                if (terminator(iter.Current))
                {
                    tx.Item2.Add(iter.Current);
                    break;
                }

                tx.Item1.Add(iter.Current);
            }

            while (iter.MoveNext())
                tx.Item2.Add(iter.Current);

            return tx;
        }      

    }//Helper

}//Craft

+1:很好,但是我认为
Skip
没有你所说的从.NET 4开始的
IList
的优化。不确定,阿尼是对的
Skip
没有针对IList的特定优化,因此列表的第一部分将始终被遍历两次。@Ani,我刚刚检查过,它似乎没有针对IList进行优化。。。我将更新我的答案。a.Count()将枚举第一个查询,需要再次枚举以获得结果。。。你需要在最后打电话给ToList(你会得到我的解决方案)我理解你的代码,但是如果(e.Current)没有意义。我认为您正在寻找存储上次
MoveNext
调用(从第一个循环)的值,并检查它是否成功。更新以使其更有意义(也就是说,一旦CheckCondition为true,将e.Current添加到
b
,而不是在循环之外处理该项,我比OP的代码更喜欢这一点,因为如果(e.Current)中没有可疑的
。理想情况下,您可以将
列表设置为headed
两次(每个列表一次)而不是每次迭代都计算。@Gabe:谢谢。我真正想避免的是重复源代码两次,并重复计算
CheckCondition
;这两个要求都在问题中说明。我不认为OP在基于标志的冗余分支方面有任何问题。:)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;



namespace Craft
{
    class Act
    {
        static void Main(string[] args)
        {

            var a = new List<string>
                { "I", "Love", "You", "More", "Today", "Than", "Yesterday" };

            var tx = a.SplitByCondition(s => s == "More");

            foreach (var s in tx.Item1)
                Console.WriteLine("First Half : {0}", s);

            foreach (var s in tx.Item2)
                Console.WriteLine("Second Half : {0}", s);

            Console.ReadLine();                    
        }

    }//Act

    public static class Helper
    {

        public static Tuple<List<T>, List<T>> SplitByCondition<T>
            (this IEnumerable<T> t, Func<T, bool> terminator)
        {


            var tx = new Tuple<List<T>, List<T>>
                          (new List<T>(), new List<T>()); 

            var iter = t.GetEnumerator();

            while (iter.MoveNext())
            {
                if (terminator(iter.Current))
                {
                    tx.Item2.Add(iter.Current);
                    break;
                }

                tx.Item1.Add(iter.Current);
            }

            while (iter.MoveNext())
                tx.Item2.Add(iter.Current);

            return tx;
        }      

    }//Helper

}//Craft
First Half : I
First Half : Love
First Half : You
Second Half : More
Second Half : Today
Second Half : Than
Second Half : Yesterday