Dictionary<比;值计数c#
本文关键字:Dictionary | 更新日期: 2023-09-27 18:05:14
我有一个像这样的字典对象:
var dictionary = new Dictionary<string, List<int>()>;
键的数量不是很大,但是值中的整数列表可以相当大(大约1000个)
给定一个键列表(keylist),我需要计算每个键的每个整数出现的次数,并按频率排序返回它们。
输出:{int1, count1}
{int2, count2}
...
这是我想到的解决方案:
var query = _keylist.SelectMany(
n=>_dictionary[n]).Group(g=>g).Select(
g=> new[] {g.key, g.count}).OrderByDescending(g=>g[1]);
即使这个查询产生了期望的结果,它的效率也不是很高。有没有一种聪明的方法可以用更少的处理产生相同的结果?
我会这样做:
var query =
from k in _keylist
from v in dictionary[k]
group v by v into gvs
let result = new
{
key = gvs.Key,
count = gvs.Count(),
}
orderby result.count descending
select result;
对我来说,这是非常直接和简单的,值得接受使用LINQ对性能的任何(轻微)影响。
另一种不会创建大组列表的方法是这样做:
var query =
_keylist
.SelectMany(k => dictionary[k])
.Aggregate(
new Dictionary<int, int>(),
(d, v) =>
{
if (d.ContainsKey(v))
{
d[v] += 1;
}
else
{
d[v] = 1;
}
return d;
})
.OrderByDescending(kvp => kvp.Value)
.Select(kvp => new
{
key = kvp.Key,
count = kvp.Value,
});
从算法空间和时间使用的角度来看,我认为唯一不理想的是当您实际上不需要组(只有组计数)时使用GroupBy
。您可以使用以下扩展方法。
public static Dictionary<K, int> CountBy<T, K>(
this IEnumerable<T> source,
Func<T, K> keySelector)
{
return source.SumBy(keySelector, item => 1);
}
public static Dictionary<K, int> SumBy<T, K>(
this IEnumerable<T> source,
Func<T, K> keySelector,
Func<T, int> valueSelector)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (keySelector == null)
{
throw new ArgumentNullException("keySelector");
}
var dictionary = new Dictionary<K, int>();
foreach (var item in source)
{
var key = keySelector(item);
int count;
if (!dictionary.TryGetValue(key, out count))
{
count = 0;
}
dictionary[key] = count + valueSelector(item);
}
return dictionary;
}
注意,其优点是数字列表是枚举的,但不存储。只存储计数。还要注意,keySelector
参数在您的示例中甚至不是必需的,我包含它只是为了使扩展方法更通用一些。
用法如下:
var query = _keylist
.Select(k => _dictionary[k])
.CountBy(n => n)
.OrderByDescending(p => p.Value);
这将使您获得KeyValuePair<int, int>
序列,其中Key
是原始列表中的数字,Value
是计数。
为了更有效地处理查询序列,你可以预处理你的数据。
Dictionary<string, Dictionary<int, int>> preprocessedDictionary
= _dictionary.ToDictionary(p => p.Key, p => p.Value.CountBy(n => n));
现在您可以更有效地执行查询。
var query = _keylist
.SelectMany(k => preprocessedDictionary[k])
.SumBy(p => p.Key, p => p.Value)
.OrderByDescending(p => p.Value);