Linq с groupby и count
Это довольно просто, но я в недоумении:
Учитывая этот тип набора данных:
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, но дал мне другой ответ.
Ответы
Ответ 1
После вызова 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
, затем сгруппируйте все элементы с той же метрикой в 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]
Ответ 2
Предполагая, что 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
.
Grouping
имеют методы расширения, такие как .Count()
, .Key()
и почти все, что вы ожидаете. Так же, как вы проверили бы .Lenght
на string
, вы можете проверить .Count()
на группе.
Ответ 3
userInfos.GroupBy(userInfo => userInfo.metric)
.OrderBy(group => group.Key)
.Select(group => Tuple.Create(group.key, group.Count()));