我可以分裂一个IEnumerable两个布尔条件没有两个查询?

我可以使用LINQ和只有一个查询/ LINQ语句将IEnumerable<T>分成两个IEnumerable<T>吗?

我想避免两次遍历IEnumerable<T> 。 例如,是否可以合并下面的最后两条语句,所以allValues只被遍历一次?

 IEnumerable<MyObj> allValues = ... List<MyObj> trues = allValues.Where( val => val.SomeProp ).ToList(); List<MyObj> falses = allValues.Where( val => !val.SomeProp ).ToList(); 

你可以使用这个:

 var groups = allValues.GroupBy(val => val.SomeProp); 

要像在你的例子中一样立即进行评估:

 var groups = allValues.GroupBy(val => val.SomeProp) .ToDictionary(g => g.Key, g => g.ToList()); List<MyObj> trues = groups[true]; List<MyObj> falses = groups[false]; 

有些人喜欢字典,但是我更喜欢查找,因为当一个关键字丢失时的行为。

 IEnumerable<MyObj> allValues = ... ILookup<bool, MyObj> theLookup = allValues.ToLookup(val => val.SomeProp); //does not throw when there are not any true elements. List<MyObj> trues = theLookup[true].ToList(); //does not throw when there are not any false elements. List<MyObj> falses = theLookup[false].ToList(); 

不幸的是,这种方法枚举了两次 – 一次创build查找,然后一次创build列表。

如果你真的不需要列表,你可以把它归结为一个单一的迭代:

 IEnumerable<MyObj> trues = theLookup[true]; IEnumerable<MyObj> falses = theLookup[false]; 

为了您的方便,复制面食延伸方法。

 public static void Fork<T>( this IEnumerable<T> source, Func<T, bool> pred, out IEnumerable<T> matches, out IEnumerable<T> nonMatches) { var groupedByMatching = source.ToLookup(pred); matches = groupedByMatching[true]; nonMatches = groupedByMatching[false]; } 

或者在C#7.0中使用元组

 public static (IEnumerable<T> matches, IEnumerable<T> nonMatches) Fork<T>( this IEnumerable<T> source, Func<T, bool> pred) { var groupedByMatching = source.ToLookup(pred); return (groupedByMatching[true], groupedByMatching[false]); } // Ex. var numbers = new [] { 1, 2, 3, 4, 5, 6, 7, 8 }; var (numbersLessThanEqualFour, numbersMoreThanFour) = numbers.Fork(x => x <= 4);