简体   繁体   English

LINQ - GroupBy 一个键,然后将每个分组的项目放入单独的“桶”中

[英]LINQ - GroupBy a key and then put each grouped item into separate 'buckets'

I have a list of items as such:我有一个这样的项目清单:

public class Item
{
    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, ie, ListId1 bucket will have all items with ListId == 1 .有没有办法让我按ListId并将它们放入每个单独的存储桶中,即ListId1存储桶将包含ListId == 1的所有项目。 The list is dynamically returned from SQL, so I don't know before hand how many ListId there will be.列表是从SQL动态返回的,所以事先不知道会有多少ListId

You can use GroupBy :您可以使用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.在此GroupBy调用之后, groupByResultIEnumerable<IGrouping<int, Item>>类型的变量,它基本上是实现IGrouping接口的对象的集合。 This allows you to iterate through all items as IGrouping is derived from IEnumerable<> and has an extra field named Key :这允许您遍历所有项目,因为IGrouping派生自IEnumerable<>并且有一个名为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 .简而言之, GroupBy方法调用返回一个列表列表 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.具体到您的示例,屏幕截图中描述了groupByResult的值。 As we can see there, your initial collection was grouped into three different buckets that have 3, 2 and 3 items, respectively.正如我们在那里看到的那样,您的初始集合被分组到三个不同的桶中,分别有 3、2 和 3 个项目。

As for accessing items in these groups, you can use simple LINQ:至于访问这些组中的项目,您可以使用简单的 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 donetFiddle 示例链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM