Как получить доступ к сгруппированным значениям, возвращаемым запросом linq

У меня есть следующий код:

List<Person> people = new List<Person>
    {
        new Person{ Id = 1, Name = "Bob"},
        new Person{ Id = 2, Name = "Joe"},
        new Person{ Id = 3, Name = "Bob"}
    };

    var peopleGroupedByName = from p in people 
                              group p by p.Name;

    //get all groups where the number of people in the group is > 1

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

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

Я был бы очень признателен за любую помощь в том, как это сделать в Linq, потому что кажется, что это должно быть очень просто.


person mezoid    schedule 30.09.2009    source источник


Ответы (3)


List<Person> people = new List<Person> {
    new Person{ Id = 1, Name = "Bob"},
    new Person{ Id = 2, Name = "Joe"},
    new Person{ Id = 3, Name = "Bob"}
};

var peopleGroupedByName = from p in people 
                          group p by p.Name into peopleGroup
                          where peopleGroup.Count() > 1
                          select peopleGroup;

//get all groups where the number of people in the group is > 1

В качестве альтернативы, where peopleGroup.Skip(1).Any(), как предположил Мердад, обычно обеспечивает лучшую производительность с Linq to Objects, поскольку Count() выполняет итерацию по всему содержимому группы, а Skip(1).Any() только по первым 2 элементам - (подробности см. в его комментарии; Count подходит для предложений group-by) .

Кроме того: для удобочитаемости я предпочитаю постоянно использовать либо синтаксис метода расширения .GroupBy(..., либо синтаксис запроса group ... by ... into ..., но не оба вместе. суб>

person Eamon Nerbonne    schedule 30.09.2009
comment
ах! в! конечно! вот чего мне не хватало! спасибо Эймон. - person mezoid; 30.09.2009
comment
Эймон: Относительно .Skip(1).Any(): это обычно повышает производительность. Чтобы быть точным, если коллекция не реализует ICollection<T> и предоставляет свойство Count, которое возвращает количество в O (1), это повышает производительность. Однако в этом конкретном случае класс Grouping, который является классом internal в System.Core, реализует Count как O(1), поэтому .Count() > 1 предпочтительнее. - person mmx; 30.09.2009

Это на самом деле довольно легко.

var filtererGroups = people
    .GroupBy(p => p.Name)
    .Where(grp => grp.Count() > 1);

Чтобы фильтровать по ключу, вы должны сделать что-то подобное.

var filtererGroups = people
    .GroupBy(p => p.Name)
    .Where(grp => grp.Key == "Bob");
person Daniel Brückner    schedule 30.09.2009

person    schedule
comment
Можно ли это сделать в синтаксисе понимания? - person mezoid; 30.09.2009
comment
Да, конечно. Просто добавьте where g.Count() > 1 к вашему запросу. - person mmx; 30.09.2009