【问题标题】:Counting the number of occurences of a number in C#在 C# 中计算一个数字的出现次数
【发布时间】:2022-01-11 19:35:59
【问题描述】:

我目前正在使用字典计算事件结果的出现次数,我将其添加如下:

IDictionary<double, double> OutcomeCounter = new Dictionary<double, double>();

public void IncrementDict(IDictionary<double, double> dict, double newKey, double increment = 1)
{
    if (!dict.ContainsKey(newKey))
    {
        dict.Add(newKey, 0);
    }
    dict[newKey] += increment;
}

但是,这占了总模拟时间的 20% 左右,我想知道你们中是否有人对如何减少它有什么好主意?

模拟产生了 100 亿个结果(总计大约 50,000 个不同的结果),因此将每个结果存储在列表中会占用太多内存。

提前致谢。

【问题讨论】:

  • 考虑使用多线程。但是字典不是线程安全的。我也避免在这里使用.Add - 只是尝试获取值然后直接分配它
  • 由于计数速度是模拟速度的四倍,因此您可以创建一个固定大小的循环队列并将结果从运行模拟的线程存储到其中。同时,运行一个单独的线程,从循环队列中取出项目并将它们添加到字典中。
  • 检查过多(ContainsAdd[])。试试if (!dict.TryAdd(newKey, increment)) dict[newKey] += increment;

标签: c# dictionary


【解决方案1】:

性能问题可能是由于字典中已经存在的数字的单次增量需要三个字典查找。每个增量都需要三个字典查找。

第一次字典查找发生在执行dict.ContainsKey(newKey) 时。第二次和第三次查找发生在dict[newKey] += increment;(一次查找从字典中获取要递增的值,另一次查找用递增的值替换旧值)。

一个想法是减少查找次数,理想情况下每次增量只有一次查找。这意味着,字典中的值一旦存储就不应更改。

实现这一点的一种方法是使用数组(或具有计数值字段的自定义类的实例,这可能比使用数组有轻微的性能优势)用作保存计数值的容器,使用保存这些容器实例的字典。由于容器实例本身仍然存在并且永远不会在字典中被替换(只有容器中的计数值会改变),所以我们只需要一次字典查找即可获得适当的容器实例。 (当然,当在新键下存储新容器实例时,需要进行额外的查找。)

例如,这可能看起来像这样。另请注意,我将计数值的类型更改为long——我不知道你为什么在这里使用double,除非你想实现小数增量(但无论long还是@,方法都是一样的987654326@,反正):

IDictionary<double, long[]> OutcomeCounter = new Dictionary<double, long[]>();

public void IncrementDict(IDictionary<double, long[]> dict, double newKey, long increment = 1)
{
    if (dict.TryGetValue(newKey, out long[] container))
    {
         container[0] += increment;
    }
    else
    {
        dict[newKey] = new long[] { increment };
    }
}

【讨论】:

  • 这太完美了!我添加了一个自定义 Counter 类,它很有效。再加上我所做的其他一些调整,该部分的处理时间减少了 10%。谢谢!
猜你喜欢
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多