#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 требует двух аргументов:
-
p => p.Group
— этот лямбда (анонимный метод) использовался для возврата ключа группировки -
(g, p) => new
GroupedPeople() { Group = g, People
= p.ToList() }Этот лямбда-код используется для создания объекта GroupedPeople на основе параметров группы, первый аргумент — это ключ группировки, выбранный первой лямбдой, второй аргумент — перечисление с элементами, относящимися к текущей группе.
Комментарии:
1. Вячеслав, не могли бы вы, пожалуйста, объяснить это более подробно? Я пытался использовать этот код, и у меня это не сработало. Что такое «g»? Я получаю следующую ошибку в VS: Не удается преобразовать лямбда-выражение в тип IEqualityComparer<string>, потому что это не тип делегата.
2. Вам нужны дополнительные сведения? Я не знаю, вам нужна информация о lambda или расширениях?
3. Работает отлично, большое спасибо. Я хотел бы отметить 2 ответа как ответы.