布尔列表检查列表中的每个项目是不是为假
Posted
技术标签:
【中文标题】布尔列表检查列表中的每个项目是不是为假【英文标题】:Bool list check if every item in list is false布尔列表检查列表中的每个项目是否为假 【发布时间】:2014-05-02 08:00:56 【问题描述】:我有一个 List<bool>
有很多值。检查列表中的每一项是否等于false
的最有效方法是什么?
【问题讨论】:
【参考方案1】:你可以使用LINQ's
All
方法:
list.All(x => x == false);
如果找到等于true
的值,它将立即返回false
。
【讨论】:
如果列表不是布尔值而是包含布尔值的类,有没有办法执行此操作? @RyanN1220 lambda 变量“x”代表这里的对象。所以您只需要更改条件x.SomeBoolProperty == false
或!x.SomeBoolProperty
【参考方案2】:
您可以使用Enumerable.Any
它会在第一次匹配时找到满足条件。正如 Habib 所说的那样,最好将 Any 用作 Enumerable。对于 Empty 的 bool 列表,All 将返回 true。
!lst.Any(c=> c == true);
或使用Enumerable.All
lst.All(c=> c == false);
【讨论】:
+1,最好使用Any
,因为Enumerable.All
将返回true
以获得一个空的布尔列表。
+1 这比 All() 执行得更好,因为它总是迭代整个列表;当它找到一个时它会停止
@AdrianCarneiro 嗯..?这对我来说没有意义。两者都很懒惰,在这种情况下需要查看相同数量的元素。
@user2864740, negated 只是为 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 @.您需要在第一条语句上使用否定运算符。【参考方案3】:
我同意使用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中相同的求值次数;在内部,对于序列实现而言,差异只是否定了对谓词和结果值的检查。
【讨论】:
如果列表不是布尔值而是包含布尔值的类,有没有办法执行此操作? @RyanN1220 是的。 LINQ 的 IEnumerable 在这方面是灵活的,因为在许多情况下都接受一个函数(例如,某些提供程序有限制,例如 LINQ-to-EF)。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)
为假。【参考方案4】:
这里没有提到的一个明显更快的解决方案是使用 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 = 0ms", timeAny);
Console.WriteLine("Elapsed via All = 0ms", timeAll);
Console.WriteLine("Elapsed via Exists = 0ms", timeExists);
Console.WriteLine("Elapsed via Contains = 0ms", timeContains);
Console.WriteLine("Contains is ~0x faster than Any!", percentFaster);
请注意,这仅适用于类型只能具有两种状态的类型(即它不适用于 >2 种状态的变量,例如 Nullable<bool>
)
【讨论】:
不错的性能比较。在有许多解决方案的地方,性能优先。 如果列表不是布尔值而是包含布尔值的类,有没有办法执行此操作? “..因为它可以在第一次出现 true.. 时提前返回。”All
和 Any
都可以(并且确实如此)。虽然Contains
可能更快,但由于提前终止而不是更快。检查.NET Reference Source's IEnumerable.All 中的实现,正如我所料,它是惰性的,不会强制评估整个序列。
@user2864740 好点 - 谢谢!我将编辑 OP 以反映这一点。以上是关于布尔列表检查列表中的每个项目是不是为假的主要内容,如果未能解决你的问题,请参考以下文章