在 C# 中分组并计数 w/ Console.WriteLine

Group by and count in C# w/ Console.WriteLine

我正在尝试 console.writeline 我的答案,但我遗漏了一些东西,经过 2 小时的搜索,我无法弄清楚。

我想让我的控制台说

Apple Large 2
Apple Mid 1
Apple Small 2

它的目标是说出类型、尺寸、将尺寸组合在一起,并说明每个尺寸有多少种尺寸 这是我的代码,任何帮助将不胜感激谢谢

namespace AppleGrouping
{
    class Program
    {
        static void Main(string[] args)
        {
            var buckets = new List<Ap>()
            {
                new Ap { Type = "Apple", Size = "Large" },
                new Ap { Type = "Apple", Size = "Small" },
                new Ap { Type = "Apple", Size = "Mid" },
                new Ap { Type = "Apple", Size = "Large" },
                new Ap { Type = "Apple", Size = "Small" },
            };

            var numberGroups = buckets.GroupBy(ap => ap.Size);
            foreach (var grp in numberGroups)
            {
                var number = grp.Key;
                var total = grp.Count();
            }

            foreach (var ap in grp)
                Console.WriteLine(ap.Type + " " + grp.Key);

        }

        public class Ap
        {
            public string Type { get; set; }

            public string Size { get; set; }
        }
    }
}

您的问题在这里:

// This stores the data in groups, with the Size as key... 
var numberGroups = buckets.GroupBy(ap => ap.Size);

// here, you're storing key and count in temporary variables, 
// but not doing anything with them. 
foreach (var grp in numberGroups)
{
    var number = grp.Key;
    var total = grp.Count();
}

将最后一位替换为:

foreach (var grp in numberGroups)
{
    Console.WriteLine("Apple " + grp.Key + "  " + grp.Count());
}

最后一个foreach循环是错误的,甚至不需要,

下面将打印出您预期的结果,

 foreach (var grp in numberGroups)
 {
    var size = grp.Key;  //I renamed number variable to size
    var total = grp.Count();
    Console.WriteLine($"{grp.First().Type} {size} {total}");
}

为什么最后一个循环是错误的?

  • 在最后一个 foreach 循环中,您试图遍历 grp 不在 class 范围内的变量。您将 grp 定义为第一个 foreach 循环的迭代器。因此 grp 变量的范围仅限于该循环。

为什么不需要最后一个循环?

  • 在您的第一个 foreach 循环中,您拥有要在控制台上打印的所有值,您只需要在同一个循环中编写 Console.WriteLine(),而不是编写单独的 foreach 循环仅用于打印详细信息。

Try online

旁注,也许有一天您的列表将包含的不仅仅是苹果,因此您也可以按类型分组并打印出来:

        var numberGroups = buckets.GroupBy(ap => new { ap.Size, ap.Type } );
        foreach (var grp in numberGroups)
        {
            var typeAndSize = grp.Key;
            var total = grp.Count();
            Console.WriteLine($"Type: {typeAndSize.Type}, Size: {typeAndSize.Size}, Count: {total}");
        }

new { ap.Size, ap.Type } 是 c# 中非常有用的工具;它被称为匿名类型,它就像编译器为我们编写的迷你 class,因此我们不必编写专用的。它做了一些典型的 classes 不做的额外事情,这使得它在分组情况下非常有用;当 GroupBy 评估一个 class 实例是否等于另一个实例时,它将使用 Equals 方法。默认情况下,它来自 Object,即 C# 中所有内容的父级 class。对象的 Equals 方法 returns 如果被比较的两个事物在 C# 中存在于相同的内存地址,则为真。这很有用,但是如果您有两个具有相同数据值但位于不同内存地址的不同对象(就像您对两个大苹果所做的那样),它会说它们不相等。这意味着如果您只是要求 GroupBy 按原样直接对对象进行分组,它不会对任何内容进行分组,因为它们都被认为彼此不相等。如果匿名类型的所有数据都相同,则匿名类型被认为是相等的,因此因为两个不同的实例都是“Large”和“Apple”,GroupBy 会将它们视为相同

(您也可以提供自己的 Equals 和 GetHashCode 版本来检查两个不同的 Ap 并比较它们的数据,以获得相同的结果,但对于此用例,使用匿名类型更容易)