使用Linq将对象列表分组为新的对象列表分组列表


149

我不知道这在Linq中是否可行,但是这里...

我有一个对象:

public class User
{
  public int UserID { get; set; }
  public string UserName { get; set; }
  public int GroupID { get; set; }
}

我返回的列表可能如下所示:

List<User> userList = new List<User>();
userList.Add( new User { UserID = 1, UserName = "UserOne", GroupID = 1 } );
userList.Add( new User { UserID = 2, UserName = "UserTwo", GroupID = 1 } );
userList.Add( new User { UserID = 3, UserName = "UserThree", GroupID = 2 } );
userList.Add( new User { UserID = 4, UserName = "UserFour", GroupID = 1 } );
userList.Add( new User { UserID = 5, UserName = "UserFive", GroupID = 3 } );
userList.Add( new User { UserID = 6, UserName = "UserSix", GroupID = 3 } );

我希望能够在上面的列表上运行一个Linq查询,该查询按GroupID将所有用户分组。因此,输出将是包含用户的用户列表的列表(如果有意义)。就像是:

GroupedUserList
    UserList
        UserID = 1, UserName = "UserOne", GroupID = 1
        UserID = 2, UserName = "UserTwo", GroupID = 1
        UserID = 4, UserName = "UserFour", GroupID = 1
    UserList
        UserID = 3, UserName = "UserThree", GroupID = 2
    UserList
        UserID = 5, UserName = "UserFive", GroupID = 3
        UserID = 6, UserName = "UserSix", GroupID = 3

我试过使用groupby linq子句,但这似乎返回一个键列表,并且未按正确分组:

var groupedCustomerList = userList.GroupBy( u => u.GroupID ).ToList();

Answers:


309
var groupedCustomerList = userList
    .GroupBy(u => u.GroupID)
    .Select(grp => grp.ToList())
    .ToList();

1
非常好,正是我所需要的。谢谢。这样做势在必行。
user1841243 2013年

1
工作正常吗?因为我习惯这种方式不起作用。objModel.tblDonars.GroupBy(t => new {t.CreatedOn.Year,t.CreatedOn.Month,t.CreatedOn.Day})。Select(g => new {tblDonar = g.ToList()))。ToList( ); 这是行不通的...您能帮忙吗?...
Rajamohan Anguchamy 2014年

与您的解决方案,它的工作正常,但我有一个问题,假设在小组中最多8个值,我只想在每个小组中只用6片,所以该怎么做,请告诉我。
coderwill '17

按GroupID分组后,有没有办法分别列出UserName和UserID?像-组ID 1的{{“ 1”,[1、2、4],[“ UserOne”,“ UserTwo”,“ UserFour”]}}
Ajay Aradhya

1
当前,如果您尝试将其强制转换为以前的列表类型,该代码将无法正常工作并导致错误。因为在select中返回一个List会在列表内创建一个Lists,这不是这里想要的输出。对于那些有问题的人,我可以建议:var groupedCustomerList = userList.GroupBy(u => u.GroupID).Select(grp => grp.First())。ToList();
aliassce

36

您的团体声明将按团体ID分组。例如,如果您然后编写:

foreach (var group in groupedCustomerList)
{
    Console.WriteLine("Group {0}", group.Key);
    foreach (var user in group)
    {
        Console.WriteLine("  {0}", user.UserName);
    }
}

那应该工作正常。每个组都有一个密钥,但也包含一个key,IGrouping<TKey, TElement>后者是一个集合,允许您遍历该组的成员。正如Lee所提到的,如果您确实愿意,可以将每个组转换为一个列表,但是,如果仅按照上面的代码遍历它们,那么这样做并没有真正的好处。


4

对于类型

public class KeyValue
{
    public string KeyCol { get; set; }
    public string ValueCol { get; set; }
}

采集

var wordList = new Model.DTO.KeyValue[] {
    new Model.DTO.KeyValue {KeyCol="key1", ValueCol="value1" },
    new Model.DTO.KeyValue {KeyCol="key2", ValueCol="value1" },
    new Model.DTO.KeyValue {KeyCol="key3", ValueCol="value2" },
    new Model.DTO.KeyValue {KeyCol="key4", ValueCol="value2" },
    new Model.DTO.KeyValue {KeyCol="key5", ValueCol="value3" },
    new Model.DTO.KeyValue {KeyCol="key6", ValueCol="value4" }
};

我们的linq查询如下所示

var query =from m in wordList group m.KeyCol by m.ValueCol into g
select new { Name = g.Key, KeyCols = g.ToList() };

或用于数组而不是下面的列表

var query =from m in wordList group m.KeyCol by m.ValueCol into g
select new { Name = g.Key, KeyCols = g.ToList().ToArray<string>() };

-1

仍然很老,但是Lee的回答并没有给我这个小组。因此,我正在使用以下语句对列表进行分组并返回分组后的列表:

public IOrderedEnumerable<IGrouping<string, User>> groupedCustomerList;

groupedCustomerList =
        from User in userList
        group User by User.GroupID into newGroup
        orderby newGroup.Key
        select newGroup;

每个组现在都有一个密钥,但还包含一个IGrouping,它是一个集合,允许您遍历该组的成员。


这回答了您的问题,而不是OP的问题。他们只想要一个列表列表。您的代码不提供该功能。
Gert Arnold

我已经发布了此解决方案,因为上面@Lee接受的答案在迭代时不起作用,因为它在迭代分组列表时提供group.key元素,如@JohnSkeet的答案所示。我提供的答案确实在迭代时提供了group.key元素。因此,可能无法帮助其他陷入陷阱的人,因为上面提供的答案无效。因此,这是获取列表的另一种方法,其好处是获得与接受的答案类似的group.key元素。不了解您的要求@GertArnold。(.net core 3.0)
数据池

我认为整个问题都基于对什么IGrouping是不了解。这就是为什么OP在底部丢弃自己的正确代码的原因,该代码您的代码基本相同。这就是为什么他们接受能够提供所要求的答案的原因。他们需要的是JS足够提供的一种解释。
Gert Arnold
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.