C#Linq All&Any在空白数组上工作不同
考虑以下空白数组的LINQ示例:
当Any()
返回false
因为没有大于零的数字, All()
返回true
表示所有大于零的数字?
var arr = new int[] { }; Console.WriteLine(arr.Any(n => n > 0)); //false Console.WriteLine(arr.All(n => n > 0)); //true
对我来说似乎合乎逻辑。
-
All
:arr
所有数字都大于零(表示不存在不大于零的数字)=>true
-
Any
:arr
中是否有大于零的数字=>false
但更重要的是,根据布尔代数 :
arr.All(n => n > 0);
给出true
,因为它应该是逻辑相反的
arr.Any(n => !(n > 0));
这给false
(其实这是以上两点说)。
All
的实现非常清楚地表明了原因。
public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw Error.ArgumentNull("source"); if (predicate == null) throw Error.ArgumentNull("predicate"); foreach (TSource element in source) { if (!predicate(element)) return false; } return true; }
它对收集运行foreach
。 如果集合中没有元素,它将跳过这个foreach
并返回true。
有趣的是,在Any
上的实现
public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw Error.ArgumentNull("source"); if (predicate == null) throw Error.ArgumentNull("predicate"); foreach (TSource element in source) { if (predicate(element)) return true; } return false; }
这个cleary显示他们是相反的。
如果列表中没有元素, All
的实现返回true:
public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw Error.ArgumentNull("source"); if (predicate == null) throw Error.ArgumentNull("predicate"); foreach (TSource element in source) { if (!predicate(element)) return false; } return true; // watch this }
这看起来很不直观,但这是如何实现的。
但是文档对于All
的返回值是非常清楚的:
如果源序列的每个元素都通过指定谓词中的testing, 或者序列为空 , 则为 true;
一些math观点: Any
和All
是||
广义版本 和&&
操作符,就像Sum
和Product
(不在LINQ中)是+
和*
概括一样。
广义操作符在空集上操作时返回中立元素的操作。 对于+
这是0,因为*
这是1所以emptyArray.Product() == 1
因为1是*
操作的中性元素(对于所有a: a * 1 == a
),对于||
这是false
( a || false == a
),对于&&
这是true
( a || true == a
)。
由于这个广义的操作符保持了“原始”操作的相关性,例如Sum: intersect(A,B) == EmptySet; S = union(A,B); S.Sum() == A.Sum() + B.Sum()
intersect(A,B) == EmptySet; S = union(A,B); S.Sum() == A.Sum() + B.Sum()
intersect(A,B) == EmptySet; S = union(A,B); S.Sum() == A.Sum() + B.Sum()
,即使集合A
或B
为空,也可以工作。 换句话说,在空集返回中性元素上定义广义运算符在math上是方便的。