Подтвердить что ты не робот

Linq отличается или группируется по нескольким свойствам

Как я могу использовать С# и Linq для получения result из следующего списка:

 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}

Я знаю, что я должен использовать GroupBy или Distinct, но понимаю, как получить то, что нужно

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

Пожалуйста, помогите

4b9b3361

Ответ 1

Он группируется по необходимым свойствам и выбирает:

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

Ответ 2

В то время как новый анонимный тип будет работать, он может иметь больше смысла, быть более читабельным и потребляемым вне вашего метода, чтобы либо создать свой собственный тип, либо использовать Tuple. (В других случаях просто использовать разделительную строку: 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();

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

Например, возможно, вы предпочтете список включенных цветов:

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

В случае простого строкового свойства для цвета может иметь смысл просто конкатенировать их. Если бы у вас было другое лицо или просто не хотелось абстрагироваться от этой информации, возможно, было бы лучше иметь другую сущность в целом, имеющую набор этого типа сущности. Например, если вы группировались по названию и цвету, вам может потребоваться показать среднюю цену или диапазон цен, где просто выбор первой из каждой группы помешает вам сделать это.

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