简体   繁体   English

统计 C# 中某个数字的出现次数

[英]Counting the number of occurences of a number in C#

I am currently counting the number of occurrences of an outcomes of an event using a dictionary, which I am adding to as follows:我目前正在使用字典计算事件结果的出现次数,我将其添加如下:

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

However, this accounts for ~20% of the total simulation time, and I was wondering if any of you had some bright ideas on how I might cut this down?然而,这占总模拟时间的 20% 左右,我想知道你们中是否有人对如何减少这个有一些好主意?

The simulation produces 10 billion outcomes (this totals to around 50,000 distinct outcomes), so storing every outcome in a list will use too much memory.模拟产生了 100 亿个结果(总计约 50,000 个不同的结果),因此将每个结果存储在列表中将使用过多的 memory。

Thanks in advance.提前致谢。

The performance problem is probably due to single increment of a number that already is in the dictionary requiring three dictionary lookups.性能问题可能是由于字典中已经存在的数字的单次增量需要三个字典查找。 Three dictionary lookups for every single increment.每个增量的三个字典查找。

The first dictionary lookup happens when executing dict.ContainsKey(newKey) .第一次字典查找发生在执行dict.ContainsKey(newKey)时。 The second and third lookup happens for dict[newKey] += increment;第二次和第三次查找发生在dict[newKey] += increment; (one lookup to obtain the value to be incremented from the dictionary, another lookup to replace the old value with the incremented value). (一个查找从字典中获取要增加的值,另一个查找用增加的值替换旧值)。

One idea is to reduce the number of lookups, ideally only one lookup per increment.一种想法是减少查找次数,理想情况下每次增量只有一次查找。 This means, the values in the dictionary should not be altered once stored.这意味着,字典中的值一旦存储就不应更改。

One approach to realize this is in using arrays (or instances of a custom class with a field for the count value, which might perhaps have a slight performance benefit over using arrays) that serve as containers holding the count values, with the dictionary holding those container instances.实现这一点的一种方法是使用 arrays (或具有计数值字段的自定义 class 的实例,这可能比使用数组有轻微的性能优势)用作保存计数值的容器,字典保存那些容器实例。 Since the container instances itself remain and won't ever be replaced in the dictionary (only the count value in the container would change), we only need one dictionary lookup to obtain the appropriate container instance.由于容器实例本身仍然存在并且永远不会在字典中被替换(只有容器中的计数值会改变),我们只需要一次字典查找即可获得适当的容器实例。 (When storing a new container instance under a new key, an additional lookup is necessary, of course.) (当然,当在新键下存储新容器实例时,需要进行额外的查找。)

This could look like this, for example.例如,这可能看起来像这样。 Also note that i changed the type of the count value to long -- i am not sure why you used double here, unless you want to realize fractional increments (but the approach will be the same whether long or double , anyways):另请注意,我将计数值的类型更改为long ——我不确定你为什么在这里使用double ,除非你想实现小数增量(但不管是long还是double ,方法都是一样的):

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

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

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