LINQ з groupby і count


222

Це досить просто, але я в збитку: враховуючи такий тип даних:

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 до 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

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

Відповіді:


396

Після виклику 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), це означає "для кожного елемента xIEnumerable, визначеного data, обчислити його .metric, а потім згрупувати всі елементи з однаковим показником у a Groupingі повернути 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

це призведе до наступного результату після групи за допомогою:

(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)". Зрозуміло "дані" - це набір даних на даний момент, але що означає "info.metric"? визначення класу?
Gio

"info.metric" - це властивість / поле метрики для класу UserInfo, про який ви згадували у своєму запитанні.
lee-m

1
Дякую, я зрозумів, що, але насправді це дає мені одне значення, а саме загальну кількість різних показників. У цьому прикладі я отримую "показники 4", що вказує мені, скільки я рахую.
Gio

1
Ого. Ви повністю пояснили групування !! Це одне було варте посади .... я стилю отримати результат "метрики 4", але дякую!
Gio

4
Початок цієї відповіді: "Після виклику GroupBy, ви отримуєте серію груп IEnumerable <Grouping>, де кожна групування розкриває сам ключ, який використовується для створення групи, а також є IEnumerable <T> будь-якими елементами, що містяться у вихідних даних набір ", - це найяскравіше пояснення LINQ GroupBy. Я ще прочитав, дякую.
dumbledad

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()));

1
маленький помилка -> group.keyв Select (...) повинна бутиgroup.Key
Jan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.