web-dev-qa-db-fra.com

linq distinct ou groupé par plusieurs propriétés

Comment puis-je utiliser c # et Linq pour obtenir un result de la liste suivante:

 var pr = new List<Product>()
   {
       new Product() {Title="Boots",Color="Red",    Price=1},
       new Product() {Title="Boots",Color="Green",  Price=1},
       new Product() {Title="Boots",Color="Black",  Price=2},

       new Product() {Title="Sword",Color="Gray", Price=2},
       new Product() {Title="Sword",Color="Green",Price=2}
   };

Result:

        {Title="Boots",Color="Red",  Price=1},               
        {Title="Boots",Color="Black",  Price=2},             
        {Title="Sword",Color="Gray", Price=2}

Je sais que je devrais utiliser GroupBy ou Distinct, mais je comprends comment obtenir ce dont j'ai besoin

   List<Product> result = pr.GroupBy(g => g.Title, g.Price).ToList(); //not working
   List<Product> result  = pr.Distinct(...);

Veuillez aider

32
user3052475

Il regroupe les propriétés requises et sélectionne:

List<Product> result = pr.GroupBy(g => new { g.Title, g.Price })
                         .Select(g => g.First())
                         .ToList();
81
Ilya

Bien qu'un nouveau type anonyme fonctionne, il pourrait être plus logique, plus lisible et consommable en dehors de votre méthode de créer votre propre type ou d'utiliser un Tuple . (D'autres fois, il peut simplement suffire d'utiliser une chaîne délimitée: string.Format({0}.{1}, g.Title, g.Price))

List<Product> result = pr.GroupBy(g => new Tuple<string, decimal>(g.Title, g.Price))
                     .ToList();

List<Product> result = pr.GroupBy(g => new ProductTitlePriceGroupKey(g.Title, g.Price))
                     .ToList();

En ce qui concerne l'obtention du jeu de résultats souhaité, la réponse fournie suggère simplement de renvoyer le premier, et peut-être que cela convient à vos besoins, mais idéalement, vous devez fournir un moyen par lequel Color est agrégé ou ignoré.

Par exemple, vous préférez peut-être lister les couleurs incluses, d'une manière ou d'une autre:

List<Product> result = pr
                     .GroupBy(g => new Tuple<string, decimal>(g.Title, g.Price))
                     .Select(x => new Product()
                             { 
                                  Title = x.Key.Item1, 
                                  Price = x.Key.Item2,
                                  Color = string.Join(", ", x.Value.Select(y => y.Color) // "Red, Green"
                             })
                     .ToList();

Dans le cas d'une propriété de chaîne simple pour la couleur, il peut être judicieux de simplement les concaténer. Si vous aviez une autre entité là-bas, ou si vous ne voulez tout simplement pas retirer ces informations, il serait peut-être préférable d'avoir une autre entité qui possède une collection de ce type d'entité. Par exemple, si vous regroupiez par titre et couleur, vous souhaiterez peut-être afficher le prix moyen ou une fourchette de prix, où le simple fait de sélectionner le premier de chaque groupe vous en empêcherait.

List<ProductGroup> result = pr
                     .GroupBy(g => new Tuple<string, decimal>(g.Title, g.Price))
                     .Select(x => new ProductGroup()
                             { 
                                  Title = x.Key.Item1, 
                                  Price = x.Key.Item2,
                                  Colors = x.Value.Select(y => y.Color)
                             })
                     .ToList();
3
JoeBrockhaus