• C#Linq中的GroupBy


    假设你有这样一个类:

    1. class Person {
    2. internal int PersonID;
    3. internal string car;
    4. }

    然后数据如下:

    1. persons[0] = new Person { PersonID = 1, car = "Ferrari" };
    2. persons[1] = new Person { PersonID = 1, car = "BMW" };
    3. persons[2] = new Person { PersonID = 2, car = "Audi" };

    然后你想根据ID建立一个映射表:

    你要怎么做?

    目录

    1. groupby

    2. ToDictionary

    3. ToLookup

    4.ToLookup和ToDictionary 对比



    1. groupby

    显然最容易想到的是用groupby,具体用法如下:

    使用Linq的版本:

    1. var results = from p in persons
    2. group p.car by p.PersonId into g
    3. select new { PersonId = g.Key, Cars = g.ToList() };

    使用函数的版本:

    1. var results = persons.GroupBy(
    2. p => p.PersonId,
    3. p => p.car,
    4. (key, g) => new { PersonId = key, Cars = g.ToList() });

    上面只是最基本的用法,实际上GroupBy的使用很灵活:

    1. class Pet
    2. {
    3. public string Name { get; set; }
    4. public double Age { get; set; }
    5. }
    6. public static void GroupByEx4()
    7. {
    8. // Create a list of pets.
    9. List petsList =
    10. new List{ new Pet { Name="Barley", Age=8.3 },
    11. new Pet { Name="Boots", Age=4.9 },
    12. new Pet { Name="Whiskers", Age=1.5 },
    13. new Pet { Name="Daisy", Age=4.3 } };
    14. // Group Pet.Age values by the Math.Floor of the age.
    15. // Then project an anonymous type from each group
    16. // that consists of the key, the count of the group's
    17. // elements, and the minimum and maximum age in the group.
    18. var query = petsList.GroupBy(
    19. pet => Math.Floor(pet.Age),
    20. pet => pet.Age,
    21. (baseAge, ages) => new
    22. {
    23. Key = baseAge,
    24. Count = ages.Count(),
    25. Min = ages.Min(),
    26. Max = ages.Max()
    27. });
    28. // Iterate over each anonymous type.
    29. foreach (var result in query)
    30. {
    31. Console.WriteLine("\nAge group: " + result.Key);
    32. Console.WriteLine("Number of pets in this age group: " + result.Count);
    33. Console.WriteLine("Minimum age: " + result.Min);
    34. Console.WriteLine("Maximum age: " + result.Max);
    35. }
    36. /* This code produces the following output:
    37. Age group: 8
    38. Number of pets in this age group: 1
    39. Minimum age: 8.3
    40. Maximum age: 8.3
    41. Age group: 4
    42. Number of pets in this age group: 2
    43. Minimum age: 4.3
    44. Maximum age: 4.9
    45. Age group: 1
    46. Number of pets in this age group: 1
    47. Minimum age: 1.5
    48. Maximum age: 1.5
    49. */
    50. }

    GroupBy里面一共有三个参数,第一个参数是主键选择器,第二个参数是指定每个组要选择的内容,第三个参数是指定要返回的对象形式。

    如果还是有点不理解可以参考这里,有更详细的解释。

    2. ToDictionary

            如果反过来,要根据汽车统计客户,那么可以使用ToDictionary函数:

    1. var dict = persons.ToDictionary(x => x.car);
    2. foreach(var x in dict)
    3. {
    4. Console.WriteLine($"Key {x.Key} {x.Value.PersonID}");
    5. }

    结果如下:

    1. Key:Ferrari ---- ID:1
    2. Key:BMW ---- ID:1
    3. Key:Audi ---- ID:2

    当然也可以指定返回类型:

    1. var dict = persons.ToDictionary(x => x.car,x=>"*"+x.PersonID+"*");
    2. Console.WriteLine(dict.Count);
    3. foreach(var x in dict)
    4. {
    5. Console.WriteLine($"Key:{x.Key} ---- ID:{x.Value}");
    6. }

    结果:

    1. 3
    2. Key:Ferrari ---- ID:*1*
    3. Key:BMW ---- ID:*1*
    4. Key:Audi ---- ID:*2*

     注意ToDictionary要求key是唯一的,如果不唯一会报错,且Value也是惟一的,不能时一个集合,如果要一对多,请往下看!

    3. ToLookup

            ToDictionary虽然很方便,不过ToLookup更好用!

            

    1. var lookupResult=persons.ToLookup(x=>x.PersonID,y=>y.car);
    2. foreach(var cars in lookupResult)
    3. {
    4. Console.WriteLine($"Person: {cars.Key}");
    5. foreach(var y in cars)
    6. {
    7. Console.WriteLine("Car Name:" + y);
    8. }
    9. }

    输出如下:

    1. Person: 1
    2. Car Name:Ferrari
    3. Car Name:BMW
    4. Person: 2
    5. Car Name:Audi

    当然Tolookup也可以传入第二个参数用于指定返回类型。看个复杂点的例子:

    1. class Package
    2. {
    3. public string Company { get; set; }
    4. public double Weight { get; set; }
    5. public long TrackingNumber { get; set; }
    6. }
    7. public static void ToLookupEx1()
    8. {
    9. // Create a list of Packages.
    10. List packages =
    11. new List
    12. { new Package { Company = "Coho Vineyard",
    13. Weight = 25.2, TrackingNumber = 89453312L },
    14. new Package { Company = "Lucerne Publishing",
    15. Weight = 18.7, TrackingNumber = 89112755L },
    16. new Package { Company = "Wingtip Toys",
    17. Weight = 6.0, TrackingNumber = 299456122L },
    18. new Package { Company = "Contoso Pharmaceuticals",
    19. Weight = 9.3, TrackingNumber = 670053128L },
    20. new Package { Company = "Wide World Importers",
    21. Weight = 33.8, TrackingNumber = 4665518773L } };
    22. // Create a Lookup to organize the packages.
    23. // Use the first character of Company as the key value.
    24. // Select Company appended to TrackingNumber
    25. // as the element values of the Lookup.
    26. ILookup<char, string> lookup =
    27. packages
    28. .ToLookup(p => p.Company[0],
    29. p => p.Company + " " + p.TrackingNumber);
    30. // Iterate through each IGrouping in the Lookup.
    31. foreach (IGrouping<char, string> packageGroup in lookup)
    32. {
    33. // Print the key value of the IGrouping.
    34. Console.WriteLine(packageGroup.Key);
    35. // Iterate through each value in the
    36. // IGrouping and print its value.
    37. foreach (string str in packageGroup)
    38. Console.WriteLine(" {0}", str);
    39. }
    40. }
    41. /*
    42. This code produces the following output:
    43. C
    44. Coho Vineyard 89453312
    45. Contoso Pharmaceuticals 670053128
    46. L
    47. Lucerne Publishing 89112755
    48. W
    49. Wingtip Toys 299456122
    50. Wide World Importers 4665518773
    51. */

    4.ToLookup和ToDictionary 对比

    1.  转为字典后关系是一对一的(一个key映射一个对象),转换后的字典是可以编辑的
    2. 转为查询是一对多的,也就是对应一个集合类型IEnumerable<>,因为ILookup<,>是不可变的
    3. 在查询结构中访问不存在的key会返回一个空序列,而在字典中会引发异常
    4.  可以初略的将 Lookup 看作 Dictionary>

    所以用谁的关键在于:多少个记录共享同一个key

  • 相关阅读:
    Windows上如何使用虚拟机安装统信uos(loongarch架构)操作系统?
    IT运维大咖带你玩转企业信息运维自动化
    Web 1.0、Web 2.0 和 Web 3.0 之间的比较
    http库requests
    逆向-beginners之float联合体
    ChatGLM系列二:ChatGLM2的介绍及代码实践
    【小5聊】sql server 分页和分组-row_number()和over()、rank()和over()的小区别
    电脑电源灯一闪一闪开不了机怎么办
    【吴恩达机器学习笔记】三、矩阵
    【ROS进阶篇】第九讲 基于Rviz和Arbotix控制的机器人模型运动
  • 原文地址:https://blog.csdn.net/q__y__L/article/details/125997669