假设你有这样一个类:
- class Person {
- internal int PersonID;
- internal string car;
- }
然后数据如下:
- persons[0] = new Person { PersonID = 1, car = "Ferrari" };
- persons[1] = new Person { PersonID = 1, car = "BMW" };
- persons[2] = new Person { PersonID = 2, car = "Audi" };
然后你想根据ID建立一个映射表:
你要怎么做?
目录
显然最容易想到的是用groupby,具体用法如下:
使用Linq的版本:
- var results = from p in persons
- group p.car by p.PersonId into g
- select new { PersonId = g.Key, Cars = g.ToList() };
使用函数的版本:
- var results = persons.GroupBy(
- p => p.PersonId,
- p => p.car,
- (key, g) => new { PersonId = key, Cars = g.ToList() });
上面只是最基本的用法,实际上GroupBy的使用很灵活:
- class Pet
- {
- public string Name { get; set; }
- public double Age { get; set; }
- }
-
- public static void GroupByEx4()
- {
- // Create a list of pets.
- List
petsList = - new List
{ new Pet { Name="Barley", Age=8.3 }, - new Pet { Name="Boots", Age=4.9 },
- new Pet { Name="Whiskers", Age=1.5 },
- new Pet { Name="Daisy", Age=4.3 } };
-
- // Group Pet.Age values by the Math.Floor of the age.
- // Then project an anonymous type from each group
- // that consists of the key, the count of the group's
- // elements, and the minimum and maximum age in the group.
- var query = petsList.GroupBy(
- pet => Math.Floor(pet.Age),
- pet => pet.Age,
- (baseAge, ages) => new
- {
- Key = baseAge,
- Count = ages.Count(),
- Min = ages.Min(),
- Max = ages.Max()
- });
-
- // Iterate over each anonymous type.
- foreach (var result in query)
- {
- Console.WriteLine("\nAge group: " + result.Key);
- Console.WriteLine("Number of pets in this age group: " + result.Count);
- Console.WriteLine("Minimum age: " + result.Min);
- Console.WriteLine("Maximum age: " + result.Max);
- }
-
- /* This code produces the following output:
- Age group: 8
- Number of pets in this age group: 1
- Minimum age: 8.3
- Maximum age: 8.3
- Age group: 4
- Number of pets in this age group: 2
- Minimum age: 4.3
- Maximum age: 4.9
- Age group: 1
- Number of pets in this age group: 1
- Minimum age: 1.5
- Maximum age: 1.5
- */
- }
GroupBy里面一共有三个参数,第一个参数是主键选择器,第二个参数是指定每个组要选择的内容,第三个参数是指定要返回的对象形式。
如果还是有点不理解可以参考这里,有更详细的解释。
如果反过来,要根据汽车统计客户,那么可以使用ToDictionary函数:
- var dict = persons.ToDictionary(x => x.car);
- foreach(var x in dict)
- {
- Console.WriteLine($"Key {x.Key} {x.Value.PersonID}");
- }
结果如下:
- Key:Ferrari ---- ID:1
- Key:BMW ---- ID:1
- Key:Audi ---- ID:2
当然也可以指定返回类型:
- var dict = persons.ToDictionary(x => x.car,x=>"*"+x.PersonID+"*");
- Console.WriteLine(dict.Count);
- foreach(var x in dict)
- {
- Console.WriteLine($"Key:{x.Key} ---- ID:{x.Value}");
- }
结果:
- 3
- Key:Ferrari ---- ID:*1*
- Key:BMW ---- ID:*1*
- Key:Audi ---- ID:*2*
注意ToDictionary要求key是唯一的,如果不唯一会报错,且Value也是惟一的,不能时一个集合,如果要一对多,请往下看!
ToDictionary虽然很方便,不过ToLookup更好用!
- var lookupResult=persons.ToLookup(x=>x.PersonID,y=>y.car);
- foreach(var cars in lookupResult)
- {
- Console.WriteLine($"Person: {cars.Key}");
- foreach(var y in cars)
- {
- Console.WriteLine("Car Name:" + y);
- }
- }
输出如下:
- Person: 1
- Car Name:Ferrari
- Car Name:BMW
- Person: 2
- Car Name:Audi
当然Tolookup也可以传入第二个参数用于指定返回类型。看个复杂点的例子:
- class Package
- {
- public string Company { get; set; }
- public double Weight { get; set; }
- public long TrackingNumber { get; set; }
- }
-
- public static void ToLookupEx1()
- {
- // Create a list of Packages.
- List
packages = - new List
- { new Package { Company = "Coho Vineyard",
- Weight = 25.2, TrackingNumber = 89453312L },
- new Package { Company = "Lucerne Publishing",
- Weight = 18.7, TrackingNumber = 89112755L },
- new Package { Company = "Wingtip Toys",
- Weight = 6.0, TrackingNumber = 299456122L },
- new Package { Company = "Contoso Pharmaceuticals",
- Weight = 9.3, TrackingNumber = 670053128L },
- new Package { Company = "Wide World Importers",
- Weight = 33.8, TrackingNumber = 4665518773L } };
-
- // Create a Lookup to organize the packages.
- // Use the first character of Company as the key value.
- // Select Company appended to TrackingNumber
- // as the element values of the Lookup.
- ILookup<char, string> lookup =
- packages
- .ToLookup(p => p.Company[0],
- p => p.Company + " " + p.TrackingNumber);
-
- // Iterate through each IGrouping in the Lookup.
- foreach (IGrouping<char, string> packageGroup in lookup)
- {
- // Print the key value of the IGrouping.
- Console.WriteLine(packageGroup.Key);
- // Iterate through each value in the
- // IGrouping and print its value.
- foreach (string str in packageGroup)
- Console.WriteLine(" {0}", str);
- }
- }
-
- /*
- This code produces the following output:
- C
- Coho Vineyard 89453312
- Contoso Pharmaceuticals 670053128
- L
- Lucerne Publishing 89112755
- W
- Wingtip Toys 299456122
- Wide World Importers 4665518773
- */
Lookup
看作 Dictionary>
所以用谁的关键在于:多少个记录共享同一个key