Використання 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();

Відповіді:


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

1
дуже приємно, просто те, що мені було потрібно. спасибі. це імперативний спосіб смокче.
користувач1841243

1
Це добре працює? тому що я звик, що ці способи не спрацювали. objModel.tblDonars.GroupBy (t => новий {t.CreateOn.Year, t.CreateOn.Month, t.CreateOn.Day}). Виберіть (g => new {tblDonar = g.ToList ()}). ); це не працює ... чи можете ви допомогти ....
Раджамохан Anguchamy

з вашим рішенням це добре працює, але у мене є одне питання, припустимо, у групі до 8 значень, і я хочу просто потрібно в кожній групі лише 6 взяти, як це зробити, будь ласка, дайте мені знати.
coderwill

чи є спосіб перерахувати імена користувача та ідентифікатори користувачів окремо після групування по GroupID? like - {"1", [1, 2, 4], ["UserOne", "UserTwo", "UserFour"]} для групиID 1.
Ajay Aradhya

1
В даний час код не працює і викликає помилку, якщо ви спробуєте передати його попередньому типу списку. Оскільки повернення списку в select створює списки всередині списку, який тут не є бажаним результатом. Для тих, хто має проблеми, я можу запропонувати: var groupedCustomerList = userList.GroupBy (u => u.GroupID) .Select (grp => grp.First ()). ToList ();
псевдонім

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 ядра 3.0)
пул даних

Я думаю, що все питання засноване на нерозумінні того, що IGroupingє. Ось чому OP відкидає власний правильний код внизу, який по суті ідентичний вашому коду. Ось чому вони приймають відповідь, яка забезпечує саме те, про що вони просять. Що їм потрібно - це пояснення, яке JS достатньо надав.
Герт Арнольд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.