c# - 将偶数和奇数分组
问题描述
我正在学习 Linq 以及如何对事物进行分组,我正在查看我以前的解决方案,我发现了这一点:
public IList<IGrouping<int, int>> GroupEvenAndOddNumbers(int[] numbers)
{
return numbers.ToLookup(x => x & 1).ToList();
}
这与我一直在进行分组的方式背道而驰,但我找不到以正常方式进行分组的方法。问题是我不明白为什么会这样,这不应该是个问题,但是知道为什么会这样会很好。我不明白的部分是“x & 1”部分。这里应用了什么逻辑?
解决方案
奇偶校验(奇/偶)
奇偶校验和二进制数之间存在有趣的相互作用。所有奇数以 结尾1
,所有偶数以 结尾0
。
想想十进制系统,以10为底。你怎么知道一个东西能被10整除?因为它以0结尾。
这适用于每个基地。在以 8 为底(八进制)中,可被 8 整除的数字以 0 结尾。在以 16 为底(十六进制)中,可被 16 整除的数字以 0 结尾。以 12345 为底,所有可被 12345 整除的数字以 0 结尾。选择任意数字,它总是有效的。
在以 2 为底(二进制)中,可被 2 整除的数字(= 偶数,根据定义)以 0 结尾。
和
&
是按位与运算符。非常简单地说,您将两个二进制值传递给它,并且对于同一位置的每个数字,它都会进行digitA AND digitB
评估。结果就是这些AND
评估的价值。
首先,AND
只有当两个输入都为真时,评估才会返回真。如果至少有一个是假的,那么结果肯定也是假的。
输入 A | 输入 B | 结果 |
---|---|---|
0 | 0 | 0 |
1 | 0 | 0 |
0 | 1 | 0 |
1 | 1 | 1 |
现在让我们看两个随机二进制数,对于每个数字位置,找出 AND 结果是什么。
10110100
10001011
-[AND]------------
10000000
请注意,仅在最左边的位置,两个位都是 1(真),因此结果也是 1(真)。在所有其他位置,两个输入数字之一中始终存在 0(假),因此结果为 0(假)
现在让我们看一个特殊情况。我将隐藏第一个数字,只显示第二个数字。试着弄清楚你已经猜到了多少结果。
????????
00000001
-[AND]------------
????????
似乎不可能,对吧?好吧,让我们考虑一下。在任何位置,如果至少有一个0,则结果肯定是0。即使我们不知道第一个数字,第二个数字已经揭示了前7位的位置肯定会导致0,因为第二个number 已经通过在这些位置使用 0 来强制执行此操作。
所以现在我们知道了:
????????
00000001
-[AND]------------
0000000?
让我们想想最后一个数字。什么时候是1,什么时候是0?在阅读下面的答案之前考虑一下。
如果第一个数字以 0 结尾,则结果也将以 0 结尾,因为
0 AND 1 = 0
.
如果第一个数字以 1 结尾,则结果也将以 1 结尾,因为1 AND 1 = 1
还记得我们之前说过的话吗?在二进制中,所有奇数以 结尾1
,所有偶数以 结尾0
。所以我们可以重写我们之前的结论说如下:
如果第一个数字是偶数,结果也将以 0 结尾,因为
0 AND 1 = 0
。
如果第一个数字是奇数,结果也将以 1 结束,因为1 AND 1 = 1
我们可以颠倒这个逻辑:
如果结果以 0 结尾,则第一个数字是偶数。
如果结果以 1 结尾,则第一个数字是奇数。
编码
numbers.ToLookup(x => x & 1).ToList()
ToLookup本质上是一个 group by 语句。它将具有相同计算值的所有元素分组在同一组中。这些组是根据计算值生成的x & 1
。
这里只有两个可能的组。使用我们的演示值,结果是00000000
或00000001
(因为前 7 位数字始终为 0,而最后一位数字可能不同)。
在标记为 的组00000000
中,您会找到以 a 结尾的所有数字0
,即所有偶数。
在标有 的组00000001
中,您会找到以 a 结尾的所有数字1
,这些数字都是奇数。
组的标签并不重要。这里重要的是你现在已经正确地分开了 evens 和 odds。
这里还有其他可能的解决方案,但它们都归结为相同的原理。另一个例子是
var evenNumbers = numbers.Where(x => x % 2 == 0).ToList();
var oddNumbers = numbers.Where(x => x % 2 == 1).ToList();
但是,位逻辑的性能往往略高一些。这是以位逻辑相当困难为代价的,但在寻找数字奇偶校验(偶数/奇数)这样简单的情况下,性能增益值得轻微的复杂性。
推荐阅读
- java - 在运行时交换 Jackson 自定义序列化器/反序列化器
- javascript - 在 ThreeJs 中使用按钮的 3d 对象移动
- python-3.x - 在python中定义矩阵时放置常量
- xml - 如何以结构化的方式将表格结构转换为纯文本
- c++ - 使用 async cpp boost socket 时减少响应时间
- mongodb - 使用 MongoDb 聚合管道根据特定类型查询前 10 项
- python - 如何有效地读取非常大的 gzip 压缩日志文件的最后一行?
- sql - 在 T-SQL 中为表创建或更改
- sql - 如何在 Presto SQL 中应用 sum() 查询并面对函数 sum 的意外参数 (varchar)
- python - 查找列表中包含重复值的每个元素的索引