我想将一个列表分成两个列表,一个可以直接处理,另一个是余数,它将通过链传递给其他处理程序。
输入:
输出:
这已经存在了吗?也许是我目前没想到的Linq方法?否则,是否有人有一个很好的C#示例?
答案 0 :(得分:19)
这是一个简单的方法。请注意,ToLookup
急切地评估输入序列。
List<int> list = new List<int> { 1, 2, 3, 4, 5, 6 };
var lookup = list.ToLookup(num => num % 2 == 0);
IEnumerable<int> trueList = lookup[true];
IEnumerable<int> falseList = lookup[false];
您可以使用GroupBy
对输入序列进行延迟评估,但它不是相当漂亮:
var groups = list.GroupBy(num => num % 2 == 0);
IEnumerable<int> trueList = groups.Where(group => group.Key).FirstOrDefault();
IEnumerable<int> falseList = groups.Where(group => !group.Key).FirstOrDefault();
答案 1 :(得分:3)
经过一些考虑和一些相当垃圾的想法,我得出结论:不要试图让LINQ为你做这件事。
有一个简单的循环消耗你的输入序列,将每个元素传递给第一个处理它的“处理程序”,并确保你的最后一个处理程序捕获所有内容或者最坏的情况返回List
而不是IEnumerable
。
public static void Handle(
IEnumerable<T> source,
Action<T> catchAll,
params Func<T, bool>[] handlers)
{
foreach (T t in source)
{
int i = 0; bool handled = false;
while (i < handlers.Length && !handled)
handled = handlers[i++](t);
if (!handled) catchAll(t);
}
}
// e.g.
public bool handleP(int input, int p)
{
if (input % p == 0)
{
Console.WriteLine("{0} is a multiple of {1}", input, p);
return true;
}
return false;
}
Handle(
source,
i => { Console.WriteLine("{0} has no small prime factor"); },
i => handleP(i, 2),
i => handleP(i, 3),
...
);
这样做的好处是可以处理输入顺序中的每个元素,而不是将它们分成组,并在随后执行任何操作之前丢失顺序。
答案 2 :(得分:2)
我同意Servy的回答,但在发表评论之后,我认为这种方法很有意思:
static class EnumerableExtensions
{
public static IEnumerable<TSource> Fork<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> filter,
Action<TSource> secondary)
{
if (source == null) throw new ArgumentNullException("source");
//...
return ForkImpl(source, filter, secondary);
}
private static IEnumerable<TSource> ForkImpl<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> filter,
Action<TSource> secondary)
{
foreach(var e in source)
if (filter(e))
yield return e;
else
secondary(e);
}
}
这可以这样使用:
var ints = new [] { 1,2,3,4,5,6,7,8,9 };
// one possible use of the secondary sequence: accumulation
var acc = new List<int>();
foreach (var i in ints.Fork(x => x % 2 == 0, t => acc.Add(t)))
{
//...
}
// later on we can process the accumulated secondary sequence
process(acc);
这里我们对二级序列进行累积(“假”值),但是这个二级序列的实时处理也是可能的,因此只需要一次枚举源。
答案 3 :(得分:0)
尽可能使用LINQ:
public IEnumerable<T> Filter(IEnumerable<T> source, Func<T, bool> criterium, out IEnumerable<T> remaining)
{
IEnumerable<T> matching = source.Where(criterium);
remaining = source.Except(matching);
return matching;
}