группировка объектов linq

#linq #group-by #linq-to-objects

#linq #группировать по #linq-to-objects

Вопрос:

У меня есть объект people, а у poeple есть группа свойств, которая делает их принадлежащими к разным группам. Я хочу получить список и поместить его в объект GrouppedPeople, в котором был бы список coll. Один элемент coll содержит только пользователей, которые принадлежат к одной группе.

Итак, если бы у меня было 3 человека:

 List<People>(){new People{Name="Test", Group = "Group1"},
               new People{Name="SameGroup", Group = "Group1"},
               new People{Name="Other", Group = "OtherGroup"}}
  

Мне нужно иметь коллекцию из 2 grouppeople. Первый будет содержать Test и SameGroup, а второй будет содержать Other (сгруппированный по свойству Group). Я пытаюсь сделать это с помощью linq.

Мне нужны результаты, которые должны иметь тип List. Grouppeople — это класс, который имеет только одно свойство типа List, и все пользователи принадлежат к одной группе.

У меня получилось что-то вроде этого:

 from oneGroup in mates
                   group oneGroup by oneGroup.pGroupName into g
                   select g;
  

Работает нормально, но результирующий объект не является строго типизированным. И я хотел бы иметь список в качестве результата. Есть ли способ получить это из этого анонимного типа объекта? Есть ли другие способы получить все это с помощью linq и сохранить строгий ввод?

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

1. Вы не потеряете строгую типизацию. Анонимные типы так же строго типизированы, как и номинальные типы. У них просто нет имени, вот и все.

2. Список какого типа вы хотите? Насколько я могу видеть, у вас должно быть IEnumerable<IGrouping<строка, люди>> в вашем существующем коде.

3. Мне нужен список<GrouppedPeople> . Grouppeople — это объект, который содержит список<Люди>.

Ответ №1:

Это вернет список объектов анонимного типа:

 var result = (from oneGroup in mates
                   group oneGroup by oneGroup.pGroupName into g
                   select g).ToList();
  

Но если вы хотите возвращать объекты определенного типа, вам следует создать новый класс с требуемыми свойствами:

 public class MateGroup
{
 public string Name {get;set;}
}

var result = (from oneGroup in mates
                   group oneGroup by oneGroup.pGroupName into g
                   select new MateGroup(){ Name =  g.<field_name>}).ToList();
  

UPD:

В соответствии с вашим комментарием, пожалуйста, попробуйте следующее:

 var result = (from oneGroup in mates
                   group oneGroup by oneGroup.pGroupName into g
                   select new GrouppedPeople(){ People =  g.ToList()}).ToList();
  

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

1. Мне нужен список<GrouppedPeople> . Grouppeople — это объект, который содержит список<Люди>. Как я могу это получить?

Ответ №2:

Что вы получите, так это IEnumerable<IGrouping<string, People>> . IGrouping<TKey, TElement> Интерфейс имеет Key , содержащий значение, по которому вы сгруппировали (в вашем случае строку, содержащую значение из Group свойства в People объекте), и вы можете перечислять по нему, чтобы получить элементы, принадлежащие группе:

 IEnumerable<IGrouping<string, People>> result = from oneGroup in mates
                group oneGroup by oneGroup.Group into g
                select g;

foreach (IGrouping<string, People> grouping in result)
{
    Console.WriteLine("Group: {0}", grouping.Key);
    foreach (People people in grouping)
    {
        Console.WriteLine(" - {0}", people.Name);
    }
}
  

Результирующий вывод (на основе ваших выборочных данных):

 Group: Group1
 - Test
 - SameGroup
Group: OtherGroup
 - Other
  

Ответ №3:

Я предпочитаю общий синтаксис C # для написания запроса LINQ, он понятнее, чем простая форма запроса.

Вы можете использовать селектор результатов, чтобы разрешить результат группировки как типизированный объект.

 var resultList = mates
    .GroupBy(p => p.Group, (g, p) => new B() { Group = g, People = p.ToList() })
    .ToList();
  

Завершите тестовый код консольного приложения:

 class People
{
    public string Name;
    public string Group;
}

class GroupedPeople
{
    public string Group;
    public List<People> People;
}

class Program
{
    static void Main(string[] args)
    {
        var mates = new List<People>()
        {
            new People{Name="Test", Group = "Group1"},
            new People{Name="SameGroup", Group = "Group1"},
            new People{Name="Other", Group = "OtherGroup"}
        };

        var resultList = mates
            .GroupBy(p => p.Group, (g, p) => new GroupedPeople() { Group = g, People = p.ToList() })
            .ToList();
    }
}
  

Вызов GroupBy требует двух аргументов:

  1. p => p.Group — этот лямбда (анонимный метод) использовался для возврата ключа группировки

  2. (g, p) => new
    GroupedPeople() { Group = g, People
    = p.ToList() }

    Этот лямбда-код используется для создания объекта GroupedPeople на основе параметров группы, первый аргумент — это ключ группировки, выбранный первой лямбдой, второй аргумент — перечисление с элементами, относящимися к текущей группе.

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

1. Вячеслав, не могли бы вы, пожалуйста, объяснить это более подробно? Я пытался использовать этот код, и у меня это не сработало. Что такое «g»? Я получаю следующую ошибку в VS: Не удается преобразовать лямбда-выражение в тип IEqualityComparer<string>, потому что это не тип делегата.

2. Вам нужны дополнительные сведения? Я не знаю, вам нужна информация о lambda или расширениях?

3. Работает отлично, большое спасибо. Я хотел бы отметить 2 ответа как ответы.