LINQ - GroupBy a key and then put each grouped item into separate 'buckets'
I have a list of items as such:
public class Item
{
开发者_JAVA技巧public int ItemId { get; set; }
public string ItemName { get; set; }
public int ListId { get; set; }
}
1 Test1 1
2 Test2 1
3 Test3 1
4 List 2
5 List2 2
6 Testing 3
7 Testing2 3
8 Testing3 3
Is there a way for me to group by the ListId
and put them into each separate buckets, i.e, ListId1
bucket will have all items with ListId == 1
. The list is dynamically returned from SQL, so I don't know before hand how many ListId
there will be.
You can use GroupBy:
var groups = items.GroupBy(item => item.ListId);
foreach(var group in groups)
{
Console.WriteLine("List with ID == {0}", group.Key);
foreach(var item in group)
Console.WriteLine(" Item: {0}", item.ItemName);
}
Let's create your list of items:
List<Item> items = new List<Item>();
items.Add(new Item() { ItemId = 1, ItemName = "Test1", ListId = 1 });
items.Add(new Item() { ItemId = 2, ItemName = "Test2", ListId = 1 });
items.Add(new Item() { ItemId = 3, ItemName = "Test3", ListId = 1 });
items.Add(new Item() { ItemId = 4, ItemName = "List", ListId = 2 });
items.Add(new Item() { ItemId = 5, ItemName = "List2", ListId = 2 });
items.Add(new Item() { ItemId = 6, ItemName = "Testing", ListId = 3 });
items.Add(new Item() { ItemId = 7, ItemName = "Testing2", ListId = 3 });
items.Add(new Item() { ItemId = 8, ItemName = "Testing3", ListId = 3 });
var groupByResult = items.GroupBy(i => i.ListId);
After this GroupBy
call, groupByResult
is a variable of type IEnumerable<IGrouping<int, Item>>
which is basically a collection of objects that implement IGrouping
interface. This allows you to iterate through all items as IGrouping
is derived from IEnumerable<>
and has an extra field named Key
:
public interface IGrouping<out TKey, out TElement> : IEnumerable<TElement>, IEnumerable
{
TKey Key { get; }
}
Briefly said, a GroupBy
method call returns a list of lists. An outer list corresponds to 'buckets' as you mentioned in your question. Then each 'bucket' contains items corresponding to that 'bucket'. To be specific to your example, the value of groupByResult
is depicted in this screenshot. As we can see there, your initial collection was grouped into three different buckets that have 3, 2 and 3 items, respectively.
As for accessing items in these groups, you can use simple LINQ:
List<Item> firstBucketItems = groupByResult.First(i => i.Key == 1).ToList();
List<Item> secondBucketItems = groupByResult.First(i => i.Key == 2).ToList();
List<Item> thirdBucketItems = groupByResult.First(i => i.Key == 3).ToList();
Or you can just iterate through all items:
foreach (var itemGroup in groupByResult)
{
int groupKey = itemGroup.Key;
foreach (Item item in itemGroup)
{
// Do whatever...
}
}
IList<Student> studentList = new List<Student>()
{
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Abram" , Age = 21 }
};
var groupedResult = from s in studentList group s by s.Age;
//iterate each group
foreach (var ageGroup in groupedResult)
{
Console.WriteLine("Age Group: {0}", ageGroup.Key); //Each group has a key
foreach(Student s in ageGroup) // Each group has inner collection
Console.WriteLine("Student Name: {0}", s.StudentName);
}
Basic format
var res = (from i in items
group i by i.ListId into g
select );
You can also do this by following
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List<Item> items = new List<Item>();
items.Add(new Item() { ItemId = 1, ItemName = "Test1", ListId = 1 });
items.Add(new Item() { ItemId = 2, ItemName = "Test2", ListId = 1 });
items.Add(new Item() { ItemId = 3, ItemName = "Test3", ListId = 1 });
items.Add(new Item() { ItemId = 4, ItemName = "List", ListId = 2 });
items.Add(new Item() { ItemId = 5, ItemName = "List2", ListId = 2 });
items.Add(new Item() { ItemId = 6, ItemName = "Testing", ListId = 3 });
items.Add(new Item() { ItemId = 7, ItemName = "Testing2", ListId = 3 });
items.Add(new Item() { ItemId = 8, ItemName = "Testing3", ListId = 3 });
var groupByResult = items.GroupBy(i => i.ListId);
List<GroupedItems> betterGroups = new List<GroupedItems>();
foreach (var groupedItem in groupByResult)
{
betterGroups.Add(new GroupedItems() { ListId = groupedItem.Key, Items = groupedItem.ToList() });
// ListId = 1 , List<Item> 3 records
// ListId = 2 , List<Item> 2 records
// ListId = 3 , List<Item> 3 records
// You can iteratre throught ListId
}
}
public class Item
{
public int ItemId { get; set; }
public string ItemName { get; set; }
public int ListId { get; set; }
}
public class GroupedItems
{
public int ListId {get; set;}
public List<Item> Items {get; set;}
}
}
donetFiddle example Link
精彩评论