繁体   English   中英

字典<>值计数c#

[英]Dictionary<> value count c#

我有这样的字典对象:

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

即使此查询产生期望的结果,它也不是很有效。 有没有一种聪明的方法可以用更少的处理来产生相同的结果?

从算法的空间和时间使用的角度来看,我看到的唯一不理想的情况是当您实际上不需要组(仅对组进行计数)时使用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);

我会这样:

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,
    });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM