在此代码段中找出GroupBy

时间:2019-04-28 16:02:06

标签: c# linq

我有一段我在努力弄清楚的代码。不知道发生了什么。它应该返回数组中出现次数最多的数字(确实如此)。 它输出以下=> [2,3]。 我试图使我的问题尽可能的易读,对您的眼睛疲劳感到抱歉。

我正在努力理解以下代码:

.GroupBy(..., numbersGroup => numbersGroup.Key),
.OrderByDescending(supergroup => supergroup.Key)
.First()

有人可以帮我解释一下此代码吗? 据我所知,我将在代码中写下注释。

int[] numbers1 = { 1, 2, 3, 3, 2, 4 };

// First in GroupBy(x => x) I group all numbers within the array (remove all
// duplicates too?), now my array looks like this [1,2,3,4].
int[] result = numbers1.GroupBy(x => x)
// In GroupBy(numbersGroup => numbersGroup.Count()) I collect all the
// different amount of occurrences withing the array, that would be 1 (1, 4)
// and 2 for (2, 3) so my array should look like this now [1, 2].
// Now this is where things get out of hand, what happens at the rest of it? I
// have tried for 4 hours now and can't figure it out. What exactly happens in
// numbersGroup => numbersGroup.Key? .OrderByDescending(supergroup => supergroup.Key)?
.GroupBy(numbersGroup => numbersGroup.Count(), numbersGroup => numbersGroup.Key)
.OrderByDescending(supergroup => supergroup.Key)
.First()
.ToArray();

2 个答案:

答案 0 :(得分:1)

带有我的评论的代码:

int[] numbers1 = { 1, 2, 3, 3, 2, 4 };

// First in GroupBy(x => x) all numbers are grouped by their values, so now data is IGrouping<int, int> query like this (formatted as a dict for readability in format {key: value}): {1: [1], 2: [2, 2], 3: [3, 3], 4: [4]} - int is key, value is occurrences list.
int[] result = numbers1.GroupBy(x => x)
// again, do GroupBy by elements count in group. You will get something like this: {1: [1, 4], 2: [2, 3]} - elements count is key, value is array of prev keys
.GroupBy(numbersGroup => numbersGroup.Count(), numbersGroup => numbersGroup.Key)
// sort groups by elements count descending: {2: [2, 3], 1: [1, 4]}
.OrderByDescending(supergroup => supergroup.Key)
// select group with max key (2): [2, 3]
.First()
// create array from this group: [2, 3]
.ToArray();

答案 1 :(得分:1)

每隔一段时间,我会遇到包含很多链接的代码,例如:

int[] noIdeaWhyThisIsAnArray = Something.DosomethingElse().AndThenAnotherThing().Etc();

每当我遇到困难时,我都会将其分解为几个步骤,并使用“ var”关键字来简化操作:

var step1 = Something.DosomethingElse();
var step2 = step1.AndThenAnotherThing();
var step3 = step2.Etc();

然后在分配了step3之后添加一个断点,运行调试器/应用程序,然后开始在Locals选项卡中签出变量。就您而言,代码如下:

int[] numbers1 = { 1, 2, 3, 3, 2, 4 };

var step1 = numbers1.GroupBy(x => x);
var step2 = step1.GroupBy(numbersGroup => numbersGroup.Count(), numbersGroup => numbersGroup.Key);
var step3 = step2.OrderByDescending(supergroup => supergroup.Key);
var step4 = step3.First();
var step5 = step4.ToArray();

Screenshot of Locals tab in the debugger

那是为了回答您的特定问题:

第一个GroupBy仅创建每个值/数字的组。因此,所有1进入第一组,然后所有2进入下一个组,所有3进入下一个组,依此类推。例如,在屏幕截图中,您可以看到第二组在其中有两个条目。它-它们都包含“ 2”。

因此,在这一点上,总共有4个组(因为有4个唯一值)。其中两个组每个都有1个值,然后其他两个组每个都有2个值。

然后按照该计数将它们分组,因此最终得到两个分组,其中的键指示每个项目的数量。因此,第一组的键为1,两个值分别为“ 1”和“ 4”,这意味着“ 1”和“ 4”都出现一次。第二组的键为2,两个值分别为“ 2”和“ 3”,这意味着“ 2”和“ 3”都出现两次。

第三步顺序导致键的降序(请记住,键指示这些值出现了多少次),因此,MOST频繁出现的数字将是结果中的第一个元素,并且最少出现的数字将是结果中的最后一个元素。

第四步只是获得第一个结果,该结果再次是MOST频繁出现的列表,在这种情况下为“ 2”和“ 3”。

最后,第五步获取该列表并将其转换为数组,因此它不是这两个Linq分组对象,而只是这两个数字的简单数组。