Utilisation de Linq pour regrouper une liste d'objets dans une nouvelle liste groupée d'objets


149

Je ne sais pas si cela est possible à Linq mais voilà ...

J'ai un objet:

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

Je renvoie une liste qui peut ressembler à ceci:

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

Je veux pouvoir exécuter une requête Linq sur la liste ci-dessus qui regroupe tous les utilisateurs par GroupID. Ainsi, la sortie sera une liste de listes d'utilisateurs contenant l'utilisateur (si cela a du sens?). Quelque chose comme:

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

J'ai essayé d'utiliser la clause groupby linq mais cela semble renvoyer une liste de clés et elle n'est pas regroupée correctement:

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

Réponses:


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

1
très sympa, exactement ce dont j'avais besoin. Merci. faire cela de manière impérative est nul.
user1841243

1
Ça marche bien? parce que je suis habitué de cette façon n'a pas fonctionné. objModel.tblDonars.GroupBy (t => new {t.CreatedOn.Year, t.CreatedOn.Month, t.CreatedOn.Day}). Sélectionnez (g => new {tblDonar = g.ToList ()}). ToList ( ); cela ne fonctionne pas ... pouvez-vous aider ....
Rajamohan Anguchamy

avec votre solution, cela fonctionne bien, mais j'ai une question supposons que dans le groupe jusqu'à 8 valeur et je veux juste avoir besoin dans chaque groupe avec seulement 6 prises, alors comment faire cela s'il vous plaît laissez-moi savoir.
coderwill

existe-t-il un moyen de lister les noms d'utilisateur et les ID utilisateur séparément après le regroupement par GroupID? comme - {"1", [1, 2, 4], ["UserOne", "UserTwo", "UserFour"]} pour groupID 1.
Ajay Aradhya

1
Actuellement, le code ne fonctionne pas et provoque une erreur si vous essayez de le convertir dans le type de liste précédent. Parce que retourner une liste dans select crée une liste à l'intérieur d'une liste qui n'est pas la sortie souhaitée ici. Pour ceux qui ont des problèmes, je peux suggérer: var groupedCustomerList = userList.GroupBy (u => u.GroupID) .Select (grp => grp.First ()). ToList ();
aliassce le

36

Votre déclaration de groupe sera regroupée par ID de groupe. Par exemple, si vous écrivez ensuite:

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

cela devrait fonctionner correctement. Chaque groupe a une clé, mais contient également un IGrouping<TKey, TElement>qui est une collection qui vous permet d'itérer sur les membres du groupe. Comme Lee le mentionne, vous pouvez convertir chaque groupe en une liste si vous le souhaitez vraiment, mais si vous allez simplement les parcourir selon le code ci-dessus, il n'y a aucun avantage réel à le faire.


4

Pour le type

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

collection

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

notre requête linq ressemble à ci-dessous

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

ou pour tableau au lieu de liste comme ci-dessous

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

Encore un ancien, mais la réponse de Lee ne m'a pas donné le groupe. Clé en conséquence. Par conséquent, j'utilise l'instruction suivante pour grouper une liste et renvoyer une liste groupée:

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

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

Chaque groupe a maintenant une clé, mais contient également un IGrouping qui est une collection qui vous permet d'itérer sur les membres du groupe.


Cela répond à votre question, pas à celle d'OP. Ils veulent seulement une liste de listes. Votre code ne fournit pas cela.
Gert Arnold

J'ai publié cette solution car la réponse acceptée ci-dessus de @Lee ne fonctionne pas lors de l'itération car elle ne fournit pas l' group.keyélément lors de l'itération dans la liste groupée comme indiqué dans la réponse de @JohnSkeet. Ma réponse fournie ne fournir l'élément group.key lorsque itérer. Cela pourrait donc aider d'autres à tomber dans le piège que les réponses fournies ne fonctionnent pas comme indiqué ci-dessus. C'est donc juste une autre façon d'obtenir la liste avec l'avantage d'obtenir l'élément group.key similaire à la réponse acceptée. Ne comprenez pas votre réclamation @GertArnold. (.net core 3.0)
datapool

Je pense que toute la question est basée sur un manque de compréhension de ce que IGroupingc'est. C'est pourquoi OP supprime son propre code correct en bas, qui est essentiellement identique à votre code. C'est pourquoi ils acceptent une réponse qui fournit exactement ce qu'ils demandent. Ce dont ils ont besoin, c'est d'une explication, que JS a suffisamment fournie.
Gert Arnold
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.