Использование 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();
lancscoder
источник

Ответы:

309
var groupedCustomerList = userList
    .GroupBy(u => u.GroupID)
    .Select(grp => grp.ToList())
    .ToList();
подветренный
источник
1
очень красиво, как раз то, что мне было нужно. Спасибо. делать это повелительным образом - отстой.
user1841243
1
Это работает нормально? потому что я использовал эти способы не работали. objModel.tblDonars.GroupBy (t => new {t.CreatedOn.Year, t.CreatedOn.Month, t.CreatedOn.Day}). Выберите (g => new {tblDonar = g.ToList ()}). ToList ( ); это не работает ... вы можете помочь ...
Раджамохан Ангучами
с вашим решением это работает нормально, но у меня есть один вопрос, предположим, в группе до 8 значений, и я хочу просто нуждаться в каждой группе всего с 6 дублями, так как, как это сделать, пожалуйста, дайте мне знать.
coderwill
Есть ли способ перечислить UserNames и UserIDs отдельно после группировки по GroupID? как - {"1", [1, 2, 4], ["UserOne", "UserTwo", "UserFour"]] для groupID 1.
Аджай Арадхья
1
В настоящее время код не работает и вызывает ошибку, если вы пытаетесь привести его к списку предыдущего типа. Потому что возвращение List в select создает списки внутри списка, который здесь не является желаемым результатом. Для тех, у кого есть проблемы, я могу предложить: var groupedCustomerList = userList.GroupBy (u => u.GroupID) .Select (grp => grp.First ()). ToList ();
aliassce
36

Ваша групповая выписка будет группироваться по идентификатору группы. Например, если вы тогда напишите:

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

это должно работать нормально. Каждая группа имеет ключ, но также содержит IGrouping<TKey, TElement>коллекцию, которая позволяет перебирать членов группы. Как упоминает Ли, вы можете преобразовать каждую группу в список, если вы действительно этого хотите, но если вы просто собираетесь их перебирать в соответствии с приведенным выше кодом, в этом нет никакой реальной выгоды.

Джон Скит
источник
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

Все еще старый, но ответ от Ли не дал мне группу. Ключ как результат. Поэтому я использую следующий оператор для группировки списка и возврата сгруппированного списка:

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

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

Каждая группа теперь имеет ключ, но также содержит IGrouping, которая представляет собой коллекцию, позволяющую перебирать членов группы.

пул данных
источник
Это отвечает на ваш вопрос, а не на вопрос ОП. Они хотят только список списков. Ваш код не обеспечивает этого.
Герт Арнольд
Я опубликовал это решение, потому что принятый выше ответ от @Lee не работает при итерации, поскольку он не предоставляет group.keyэлемент при итерации по сгруппированному списку, как показано в ответе @JohnSkeet. Мой ответ при условии , действительно обеспечивает элемент group.key когда итерация. Таким образом, это может помочь другим попасть в ловушку, что предоставленные ответы не работают, как показано выше. Так что это просто еще один способ получить список с преимуществом получения элемента group.key, аналогичного принятому ответу. Не понимаю ваше требование @GertArnold. (.net core 3.0)
пул данных
Я думаю, что весь вопрос основан на непонимании того, что IGroupingесть. Вот почему OP отбрасывает свой собственный правильный код внизу, который по сути идентичен вашему коду. Вот почему они принимают ответ, который обеспечивает именно то, что они просят. Что им нужно, так это объяснение, которое JS в достаточной мере предоставило.
Герт Арнольд