Группировать по отдельности с помощью Linq

#c# #linq #group-by #distinct

#c# #linq #группировать по #distinct

Вопрос:

Я хочу четко объединить две или более коллекций по идентификатору и создать коллекцию другого свойства для каждого идентификатора.

У меня есть объект foo

 public class foo
{
    public int id { get; set; }
    public string color { get; set; }
}
  

Которых у меня несколько, List<foo> которые имеют общие идентификаторы, но с разными цветами

 //list 1
id = 1, color = "red"
id = 2, color = "blue"
id = 3, color = "green"
id = 1, color = "blue"
id = 2, color = "orange"
//list 2                
id = 1, color = "black"
id = 2, color = "amber"
id = 3, color = "red"
id = 4, color = "red"
id = 2, color = "silver"
  

Я хочу использовать linq для создания новой коллекции, которая будет отличаться по идентификатору, но создавать и перечислять свойство color.

 id = 1, color = { "red", "blue", "black" }
id = 2, color = { "blue", "orange", "amber", "silver" }
id = 3, color = { "green", "red" }
id = 4, color = { "red" }
  

Вопрос: Как это можно записать в linq

Ответ №1:

 var colours = list.GroupBy(x => x.id)
                  .Select(x => new {id = x.Key, color = x.Select(y => y.color).ToList()})
                  .ToList();
  

Это даст вам список с именем colors в нужной вам структуре.

Если вы хотите, чтобы поле цвета представляло собой строку, разделенную запятой, измените ее на:

 var colours = list.GroupBy(x => x.id)
                  .Select(x => new {id = x.Key, color = x.Select(y => y.color).ToArray().Join(",")})
                  .ToList();
  

Комментарии:

1. Да, я собрал два списка вместе, сейчас пытаюсь это решение @Kevin Holditch

2. Также отсутствуют закрывающие фигурные скобки @Kevin Holditch

3. Мой плохой, теперь все исправлено 🙂

4. Выбор «создать» создаст анонимный список типов, верно? Есть ли способ сделать это без создания анонимного типа?

Ответ №2:

Я думаю, вы хотите Dictionary<int, List<string>> вместо:

 Dictionary<int, List<string>> idColors = foos
    .GroupBy(f => f.id)
    .ToDictionary(g => g.Key, g => g.Select(f => f.color).ToList());
  

Теперь вы можете получить доступ к цветам каждого идентификатора таким образом:

 List<string> colors = idColors[1];
Console.WriteLine(string.Join(",", colors));
  

Ответ №3:

 var result = List.GroupBy(g => new { g.id, g.color })
                         .Select(g => g.First())
                         .ToList();
  

Комментарии:

1. Возможно, вам потребуется добавить Concat вызов, чтобы продемонстрировать объединение обоих List<Foo> списков вместе.

2. Есть два списка, и для этого используется только первый цвет каждой группы … результат должен включать все цвета

Ответ №4:

вы можете использовать приведенный ниже код

 var mergedList = list1.Concat(list2)
                  .GroupBy(person => person.id)
                  .Select(group => group.Aggregate(
                                     (merged, next) => merged.Merge(next)))
                  .ToList();
  

Ответ №5:

Я думаю, это то, что вы ищете:

 list1.Concat(list2)
    .GroupBy(x => x.id)
    .Select(x => new foo 
                   {  
                      id = x.Key, 
                      color = string.Join(",", x.Select(g => g.color)) 
                   }).ToList();
  

Ответ №6:

Попробуйте это:

  var combinedList = list1;
 combinedList.AddRange(list2);
 var uniqueIds = combinedList.Select(p => p.id).Distinct()

 var result = new Dictionary<int, List<string>>();
 uniqueIds.ForEach(i => result.Add(i, new List<string>());
 combinedList.ForEach(i => result[i.id].Add(i.color);
  

Я не тестировал это, но я думаю, что все должно быть в порядке…
Возможно, это лучший способ сделать это, но на данный момент это должно заставить вас работать!