LINQ с групповым и графом

221

Это довольно просто, но я в растерянности: учитывая этот тип набора данных:

UserInfo(name, metric, day, other_metric)

и этот пример набора данных:

joe  1 01/01/2011 5
jane 0 01/02/2011 9
john 2 01/03/2011 0
jim  3 01/04/2011 1
jean 1 01/05/2011 3
jill 2 01/06/2011 5
jeb  0 01/07/2011 3
jenn 0 01/08/2011 7

Я хотел бы получить таблицу, в которой перечислены метрики по порядку (0,1,2,3 ..) с общим числом раз, когда происходит подсчет. Таким образом, из этого набора вы бы в конечном итоге:

0 3    
1 2    
2 2    
3 1

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

POST Edit: мне никогда не удавалось заставить опубликованные ответы работать, поскольку они всегда возвращали одну запись с количеством различных подсчетов. Однако я смог собрать пример LINQ to SQL, который работал:

        var pl = from r in info
                 orderby r.metric    
                 group r by r.metric into grp
                 select new { key = grp.Key, cnt = grp.Count()};

Этот результат дал мне упорядоченный набор записей с «метриками» и количеством пользователей, связанных с каждым. Я явно новичок в LINQ в целом, и на мой неопытный взгляд этот подход кажется очень похожим на чистый подход LINQ, но дал мне другой ответ.

Gio
источник
Да, но объяснения Джимми помогли мне больше. Однако я так и не смог заставить его пример работать, но это привело меня в новое русло.
Gio
@Jimmy использовал функциональный синтаксис для выражений LINQ, а не стандартный синтаксис запросов LINQ, плюс он решил показать немедленное выполнение этих функций, а не формат отложенного выполнения. Для нового человека это будет сбивать с толку. Не знаю, почему он это сделал.
Ричард Робертсон

Ответы:

395

После вызова GroupByвы получаете серию групп IEnumerable<Grouping>, где каждая группировка сама выставляет Keyиспользуемые для создания группы, а также представляет собой IEnumerable<T>любой элемент в вашем исходном наборе данных. Вам просто нужно вызвать Count()эту Группировку, чтобы получить промежуточный итог.

foreach(var line in data.GroupBy(info => info.metric)
                        .Select(group => new { 
                             Metric = group.Key, 
                             Count = group.Count() 
                        })
                        .OrderBy(x => x.Metric)
{
     Console.WriteLine("{0} {1}", line.Metric, line.Count);
}


Это был блестящий быстрый ответ, но у меня возникла небольшая проблема с первой строкой, а именно: data.groupby (info => info.metric) "

Я предполагаю, что у вас уже есть список / массив некоторых, classкоторые выглядят как

class UserInfo {
    string name;
    int metric;
    ..etc..
} 
...
List<UserInfo> data = ..... ;

Когда вы это сделаете data.GroupBy(x => x.metric), это означает, что «для каждого элемента xв IEnumerable, определенного посредством data, вычислите его .metric, затем сгруппируйте все элементы с одинаковой метрикой в ​​a Groupingи верните a IEnumerableиз всех полученных групп. Учитывая ваш примерный набор данных

    <DATA>           | Grouping Key (x=>x.metric) |
joe  1 01/01/2011 5  | 1
jane 0 01/02/2011 9  | 0
john 2 01/03/2011 0  | 2
jim  3 01/04/2011 1  | 3
jean 1 01/05/2011 3  | 1
jill 2 01/06/2011 5  | 2
jeb  0 01/07/2011 3  | 0
jenn 0 01/08/2011 7  | 0

это приведет к следующему результату после groupby:

(Group 1): [joe  1 01/01/2011 5, jean 1 01/05/2011 3]
(Group 0): [jane 0 01/02/2011 9, jeb  0 01/07/2011 3, jenn 0 01/08/2011 7]
(Group 2): [john 2 01/03/2011 0, jill 2 01/06/2011 5]
(Group 3): [jim  3 01/04/2011 1]
Джимми
источник
Это был блестящий быстрый ответ, но у меня возникла небольшая проблема с первой строкой, а именно: data.groupby (info => info.metric) ". Проще говоря, «data» - это текущий набор данных, но что представляет собой «info.metric»? определение класса?
Gio
«info.metric» будет метрическим свойством / полем в классе UserInfo, который вы упомянули в своем вопросе.
Ли-м
1
Спасибо, что понял, но на самом деле это, кажется, дает мне одно значение - а именно общее количество различных метрических показателей. В этом примере я получаю «метрику 4», которая показывает мне, сколько у меня разных показателей.
Gio
1
Вот это да. Вы полностью объяснили группировку !! Одно это стоило поста ... я все еще получаю результат "metrics 4", но спасибо!
Gio
4
Начало этого ответа: «после вызова GroupBy вы получаете серию групп IEnumerable <Grouping>, где каждая группа сама выставляет ключ, используемый для создания группы, а также представляет собой IEnumerable <T> любых элементов в ваших исходных данных. set ", является самым ясным объяснением LINQ Group. Я только что прочитал, спасибо.
Дамблдад
48

Предполагая userInfoListэто List<UserInfo>:

        var groups = userInfoList
            .GroupBy(n => n.metric)
            .Select(n => new
            {
                MetricName = n.Key,
                MetricCount = n.Count()
            }
            )
            .OrderBy(n => n.MetricName);

Лямбда-функция для GroupBy(), n => n.metricозначает, что она будет получать поле metricот каждого UserInfoобнаруженного объекта. Тип nзависит от контекста, в первом случае это тип UserInfo, потому что список содержит UserInfoобъекты. Во втором случае nэто тип Grouping, потому что теперь это список Groupingобъектов.

Groupings имеют методы расширения , как .Count(), .Key()и почти все , что еще можно было бы ожидать. Точно так же, как вы можете проверить .Lenghtна string, вы можете проверить .Count()на группу.

Владислав Зоров
источник
23
userInfos.GroupBy(userInfo => userInfo.metric)
        .OrderBy(group => group.Key)
        .Select(group => Tuple.Create(group.Key, group.Count()));
DanielOfTaebl
источник
1
маленькая опечатка -> group.keyв Select (...) должна бытьgroup.Key
Jan