Verwenden von Linq zum Gruppieren einer Liste von Objekten in einer neuen gruppierten Liste von Objektlisten

149

Ich weiß nicht, ob dies in Linq möglich ist, aber hier geht es weiter ...

Ich habe ein Objekt:

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

Ich gebe eine Liste zurück, die wie folgt aussehen könnte:

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 } );

Ich möchte in der obigen Liste eine Linq-Abfrage ausführen können, die alle Benutzer nach GroupID gruppiert. Die Ausgabe ist also eine Liste von Benutzerlisten, die Benutzer enthält (wenn das sinnvoll ist?). Etwas wie:

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

Ich habe versucht, die groupby linq-Klausel zu verwenden, aber dies scheint eine Liste von Schlüsseln zurückzugeben, die nicht korrekt gruppiert ist:

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

Antworten:

309
var groupedCustomerList = userList
    .GroupBy(u => u.GroupID)
    .Select(grp => grp.ToList())
    .ToList();
Lee
quelle
1
sehr schön, genau das was ich brauchte. Danke. dies auf die zwingende Weise zu tun, ist scheiße.
user1841243
1
Funktioniert es gut? weil ich so benutzt werde, hat es nicht funktioniert. objModel.tblDonars.GroupBy (t => new {t.CreatedOn.Year, t.CreatedOn.Month, t.CreatedOn.Day}). Wählen Sie (g => new {tblDonar = g.ToList ()}). ToList ( ); das funktioniert nicht ... kannst du helfen ...
Rajamohan Anguchamy
Mit Ihrer Lösung funktioniert es einwandfrei, aber ich habe eine Frage in der Gruppe mit bis zu 8 Werten und ich möchte nur in jeder Gruppe mit nur 6 nehmen, also wie kann ich das tun, lassen Sie es mich bitte wissen.
Coderwill
Gibt es eine Möglichkeit, Benutzernamen und Benutzer-IDs nach der Gruppierung nach Gruppen-ID separat aufzulisten? wie - {"1", [1, 2, 4], ["UserOne", "UserTwo", "UserFour"]} für Gruppen-ID 1.
Ajay Aradhya
1
Derzeit funktioniert der Code nicht und verursacht einen Fehler, wenn Sie versuchen, ihn in den vorherigen Listentyp umzuwandeln. Da durch das Zurückgeben einer Liste in select eine Liste in einer Liste erstellt wird, die hier nicht die gewünschte Ausgabe ist. Für diejenigen, die Probleme haben, kann ich vorschlagen: var groupedCustomerList = userList.GroupBy (u => u.GroupID) .Select (grp => grp.First ()). ToList ();
Aliassce
36

Ihre Gruppenanweisung wird nach Gruppen-ID gruppiert. Zum Beispiel, wenn Sie dann schreiben:

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

das sollte gut funktionieren. Jede Gruppe hat einen Schlüssel, enthält aber auch einen, bei IGrouping<TKey, TElement>dem es sich um eine Sammlung handelt, mit der Sie die Mitglieder der Gruppe durchlaufen können. Wie Lee erwähnt, können Sie jede Gruppe in eine Liste konvertieren, wenn Sie dies wirklich möchten. Wenn Sie sie jedoch nur gemäß dem obigen Code durchlaufen möchten, hat dies keinen wirklichen Vorteil.

Jon Skeet
quelle
4

Für Typ

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

Sammlung

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" }
};

Unsere Linq-Abfrage sieht wie folgt aus

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

oder für Array anstelle von Liste wie unten

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

Immer noch eine alte, aber die Antwort von Lee gab mir nicht die Gruppe. Schlüssel als Ergebnis. Daher verwende ich die folgende Anweisung, um eine Liste zu gruppieren und eine gruppierte Liste zurückzugeben:

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

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

Jede Gruppe hat jetzt einen Schlüssel, enthält aber auch eine IGrouping, eine Sammlung, mit der Sie über die Mitglieder der Gruppe iterieren können.

Datenpool
quelle
Dies beantwortet Ihre Frage, nicht die Frage von OP. Sie wollen nur eine Liste von Listen. Ihr Code bietet das nicht.
Gert Arnold
Ich habe diese Lösung veröffentlicht, da die oben von @Lee akzeptierte Antwort beim Iterieren nicht funktioniert, da sie das Element beim Durchlaufen der gruppierten Liste nicht bereitstellt, group.keywie in der Antwort von @JohnSkeet gezeigt. Meine bereitgestellte Antwort enthält das Element group.key beim Iterieren. Es könnte also anderen helfen, in die Falle zu tappen, dass die bereitgestellten Antworten nicht wie oben gezeigt funktionieren. Es ist also nur eine andere Möglichkeit, die Liste mit dem Vorteil abzurufen, dass das group.key-Element ähnlich der akzeptierten Antwort abgerufen wird. Verstehe deinen Anspruch @GertArnold nicht. (.net Core 3.0)
Datenpool
Ich denke, die ganze Frage basiert auf Unverständnis darüber, was IGroupingist. Aus diesem Grund verwerfen OP unten ihren eigenen korrekten Code, der im Wesentlichen mit Ihrem Code identisch ist . Deshalb akzeptieren sie eine Antwort, die genau das liefert, wonach sie fragen. Was sie brauchen, ist eine Erklärung, die JS ausreichend zur Verfügung gestellt hat.
Gert Arnold