给定项目集合,如何根据谓词将集合拆分为2个子集合?
你可以做2次搜索,但是运行时间是2 * N(虽然仍然是O(n),需要两倍的时间,显然不是首选)
IEnumerable<int> even = nums.Where(i => IsEven(i));
IEnumerable<int> odd = nums.Where(i => !IsEven(i));
你可以自己做一个线性传递(在这里重构为扩展方法),但这意味着你必须全部拖动这些代码,而更多的自定义代码使得事情的可维护性降低。
public static void SplitOnPred<T>(
this IEnumerable<T> collection,
Func<T, bool> pred,
out IEnumerable<T> trueSet,
out IEnumerable<T> falseSet
) {
List<T> trueSetList = new List<T>();
List<T> falseSetList = new List<T>();
foreach( T item in collection ) {
if( pred( item ) ) {
trueSetList.Add( item );
} else {
falseSetList.Add( item );
}
}
trueSet = trueSetList;
falseSet = falseSetList;
}
问题: LINQ是否有任何原生支持在1个线性传递中拆分集合?
答案 0 :(得分:27)
LINQ是否有任何本机支持在1个线性传递中拆分集合?
没有内置方法可以根据谓词将集合拆分为两个版本。您需要使用自己的方法,类似于您发布的方法。
最接近的内置方法是GroupBy
(或ToLookup
)。你可以按奇数或偶数分组:
var groups = nums.GroupBy(i => IsEven(i));
根据数字是奇数还是偶数,这将分成两个“组”。
答案 1 :(得分:8)
Reed Copsey的回答提到ToLookup
,这似乎很有吸引力。
var lookup = nums.ToLookup(IsEven);
其中IsEven
是具有预期签名和返回类型的静态方法。然后
IEnumerable<int> even = lookup[true];
IEnumerable<int> odd = lookup[false];
答案 2 :(得分:5)
如果逻辑是独占的,在你的情况中,你可以这样做
var list = new List<int> {1,2,3,4,5,6,7,8,9,10};
var result = list.GroupBy(x=> x%2==0);
并在result
foreach(var r in result)
{
if(r.Key)
//EVEN
else
//ODD
}
答案 3 :(得分:1)
如果您想支持延迟执行,请使用如下函数或扩展名:
IEnumerable<T> Split<T>(this IEnumerable<T> source, out IEnumerable<T> odd)
{
IList<T> oddCollector = new List<T>();
Bool odd = true;
foreach(T item in source)
{
if(odd)
{
oddCollector.Add(item);
}
else
{
yield return item;
}
odd = !odd;
}
}
我对任何小编译器错误表示歉意,我是从头脑中做到的。您可以添加谓词,而不是偶数/奇数。