29

给定一个项目集合,如何根据谓词将集合拆分为 2 个子集合?

你可以做 2 Where 搜索,但是运行时间是 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 个线性通道中拆分集合有任何原生支持?

4

4 回答 4

29

LINQ 是否对在 1 个线性通道中拆分集合有任何本机支持?

没有内置方法可以根据谓词将集合拆分为两个版本。您需要使用自己的方法,类似于您发布的方法。

最接近的内置方法是GroupBy(或ToLookup)。您可以按奇数或偶数分组:

var groups = nums.GroupBy(i => IsEven(i));

这将根据数字是奇数还是偶数分为两个“组”。

于 2012-08-13T17:02:04.017 回答
11

Reed Copsey 的回答提到ToLookup了 ,这似乎很有吸引力。

var lookup = nums.ToLookup(IsEven);

whereIsEven是具有预期签名和返回类型的静态方法。然后

IEnumerable<int> even = lookup[true];
IEnumerable<int> odd = lookup[false];
于 2012-08-13T18:16:27.840 回答
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
}
于 2012-08-13T17:04:20.460 回答
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;
   }
 }

对于任何小的编译器错误,我深表歉意,我是从头顶上做的。您可以添加谓词,而不是偶数/奇数。

于 2013-07-17T15:03:24.013 回答