【发布时间】:2014-05-02 08:00:56
【问题描述】:
我有一个 List<bool> 有很多值。检查列表中的每一项是否等于false 的最有效方法是什么?
【问题讨论】:
我有一个 List<bool> 有很多值。检查列表中的每一项是否等于false 的最有效方法是什么?
【问题讨论】:
你可以使用LINQ'sAll方法:
list.All(x => x == false);
如果找到等于true 的值,它将立即返回false。
【讨论】:
x.SomeBoolProperty == false 或!x.SomeBoolProperty
您可以使用Enumerable.Any 它会在第一次匹配时找到满足条件。正如 Habib 所说的那样,最好将 Any 用作 Enumerable。对于 Empty 的 bool 列表,All 将返回 true。
!lst.Any(c=> c == true);
lst.All(c=> c == false);
【讨论】:
Any,因为Enumerable.All 将返回true 以获得一个空的布尔列表。
Any 提供 bool 值的一种简单方式,考虑以下代码:List<bool> list = new List<bool>(); var b1 = list.All(r => r == false); var b2 = list.Any(r => r == false);,现在 b1 将是 true 和 b2是假的。只是Enumerable.All 在空列表上的行为不同。
true,则首先返回true,如果所有项目都等于@987654337,则返回true @.您需要在第一条语句上使用否定运算符。
我同意使用IEnumerable.Any/All。但是,我不同意当前投票最多的答案(在撰写本文时这是错误的)以及 Any vs All 的几个相关 cmet。
以下这些操作在语义上是等价的。请注意,否定都应用在谓词内部和运算结果上。
!l.Any(x => f(x))
l.All(x => !f(x))
现在,在这种情况下,我们正在寻找:
如果是不则有任何真值。
!l.Any(x => x) // f(x) = x == true
或者,
每个值都是不为真。
l.All(x => !x) // f'(x) = !f(x) = !(x == true)
空列表没有什么特别的,结果是一样的:例如!empty.Any(..) 是假的,empty.All(..) 也是假的,上面的等价关系仍然有效。
另外,两种表单都是惰性求值的,需要LINQ To Objects中相同的求值次数;在内部,对于序列实现而言,差异只是否定了对谓词和结果值的检查。
【讨论】:
All/Any 函数采用可选的Func<T, bool>。在上面,f(x) 是一个“一些代码”(和/或一个函数),它接受 x 并返回一个布尔值。例如,给定var a = new [] { Tuple.Create(1, true), Tuple.Create(1, false) },则a.Any(x => x.Item2) 为真,a.All(x => x.Item2) 为假。
这里没有提到的一个明显更快的解决方案是使用 Contains
if (!myList.Contains(true))
// Great success - all values false!
我将Contains 与IEnumerable.Any 进行了比较,Contains 的返回速度更快。在我的测试中,IEnumerable.All 的性能与IEnumerable.Any 相同,可能在后台对这两个功能使用了类似的算法。我还检查了IEnumerable.Exists,它的性能优于IEnumerable.Any 和IEnumerable.All,但仍然比Contains 慢。
在 10,000,000 个布尔条目列表中(我也尝试了 0 和 1 个条目,结果相似),我得出了以下指标:
经过任何 = 95ms
全部经过 = 88 毫秒
经过 Exists = 27ms
经过包含 = 17ms
Contains 比 Any 快约 5.59 倍!
用以下代码测试:
// setup initial vars
var myList = new List<bool>();
for (int x = 0; x < 10000000; x++)
myList.Add(false);
var containsAllFalse = false;
Stopwatch sw = new Stopwatch();
// start test
sw.Start();
containsAllFalse = !myList.Any(x => x);
sw.Stop();
// get result for Any
var timeAny = sw.ElapsedMilliseconds;
// reset variable state (just in case it affects anything)
containsAllFalse = false;
// start test 2
sw.Restart();
containsAllFalse = myList.All(x => x == false);
sw.Stop();
// get result for All
var timeAll = sw.ElapsedMilliseconds;
// reset variable state (just in case it affects anything)
containsAllFalse = false;
// start test 3
sw.Restart();
containsAllFalse = !myList.Exists(x => x == true);
sw.Stop();
// get result for All
var timeExists = sw.ElapsedMilliseconds;
// reset variable state (just in case it affects anything)
containsAllFalse = false;
// start test 4
sw.Restart();
containsAllFalse = !myList.Contains(true);
sw.Stop();
// get result from Contains
var timeContains = sw.ElapsedMilliseconds;
// print results
var percentFaster = Math.Round((double)timeAny / timeContains, 2);
Console.WriteLine("Elapsed via Any = {0}ms", timeAny);
Console.WriteLine("Elapsed via All = {0}ms", timeAll);
Console.WriteLine("Elapsed via Exists = {0}ms", timeExists);
Console.WriteLine("Elapsed via Contains = {0}ms", timeContains);
Console.WriteLine("Contains is ~{0}x faster than Any!", percentFaster);
请注意,这仅适用于类型只能具有两种状态的类型(即它不适用于 >2 种状态的变量,例如 Nullable<bool>)
【讨论】:
All 和 Any 都可以(并且确实如此)。虽然Contains 可能更快,但由于提前终止而不是更快。检查.NET Reference Source's IEnumerable.All 中的实现,正如我所料,它是惰性的,不会强制评估整个序列。