“我该怎么做?”;“合并”;将多个词典合并为一个;“聚合”;在C#中?

“我该怎么做?”;“合并”;将多个词典合并为一个;“聚合”;在C#中?,c#,dictionary,collections,hashtable,C#,Dictionary,Collections,Hashtable,我有以下情况: 函数GetDict()返回一个Dictionary对象,并在循环中被调用若干次(这个数字由用户指定)。返回的字典总是保证包含相同的键集(我现在假设这是为了简单起见) 我的目标是最终获得每个键返回的所有值的平均值: public Dictionary<double, double> CalculateAveragePerKey(int N) { var aggregateDict = new Dictionary<double, double>();

我有以下情况:

函数
GetDict()
返回一个
Dictionary
对象,并在循环中被调用若干次(这个数字由用户指定)。返回的字典总是保证包含相同的键集(我现在假设这是为了简单起见)

我的目标是最终获得每个键返回的所有值的平均值:

public Dictionary<double, double> CalculateAveragePerKey(int N)
{
    var aggregateDict = new Dictionary<double, double>();

    for(int i=0; i < N; i++)
    {
        var returnedDict = GetDict();
        // aggregateDict -- how to calculate an average of values for each key?
    }

    return aggregateDict;
}

public Dictionary<double, double> GetDict()
{
    var newDict = new Dictionary<double, double>();
    // populate the newDict, always guaranteed (assumed for simplicity)
    // to contain the same set of keys ...
    return newDict;
}
公共字典计算rageperkey(int N)
{
var aggregateDict=新字典();
对于(int i=0;i
因此,如果N=3且在循环中,返回的字典包含键
10.0
的值
1.0
2.3
3.0
,在
aggregateDict
末尾,键
10.0
的值应为
2.1


如果这不是解决此类问题的最佳数据结构或方法,我肯定可以重构代码以使用其他数据结构或方法。我只是在寻找最有效的方法。

您可以通过两个步骤修改代码来计算平均值:

  • 在循环中调用
    GetDict()
    时,检查其键,并将值添加到
    aggregateDict的值中
  • 循环结束后,再次遍历这些值,并将它们除以
    N
您还可以在循环内将
GetDict()
的值除以
N
,具体取决于在
GetDict()
中获得的值的分布

您也可以在不使用循环的情况下使用LINQ执行此操作,如下所示:

var avg = Enumerable
    .Range(0, N)
    .SelectMany(n => GetDict())
    .GroupBy(p => p.Key)
    .ToDictionary(
            g => g.Key
        ,   g => g.Sum(p => p.Value) / g.Count()
        );

请注意,在使用
double
作为字典键时需要非常小心,因为浮点类型本质上是不精确的。因此,您可能会看到两个非常接近的数字映射到不同的字典键。

double
对于字典键来说是一种非常糟糕的类型,因为浮点精度错误通常会导致您期望相等的数字不相等,再加上基于散列的结构不能真正处理模糊相等的事实,我没有想到这一点。那我还能怎么解决这个问题呢?我应该使用二维数组来存储键值对吗?(我也可以在预处理期间在GetDict()中将我的键转换为int,但有更好的选择吗?)?你自己试过解决这个问题了吗?如果这些数字是以十为基数的精确数字的表示,你可能应该使用
decimal
而不是
double
。@MgSam,不,这是我正在编写的一个更大程序的一部分,该程序在某些数据集上多次运行算法,并以这种方式组合结果。我最初将所有数据存储在二维数组(而不是DICT)中,并循环计算平均值,但由于我的数据是以键值对的形式存在的,我希望这种方法可能会更有效。谢谢,我正在考虑重写一些逻辑,将我的键转换为整数。一个后续问题-我的数据集由大约30k个键值对组成。LINQ是最有效的方法吗?我最初使用的是您提到的“在所有值上循环”方法,但由于我的数据集太大,我想知道它是否有效。@ubuntunob如果数字
N
为10或更多,请使用您的方法(见答案顶部),因为它使用的内存更少。就计时而言,使用LINQ与否无关紧要,因为无论哪种方式,计时顺序都是
K*N
,其中
K
是键的数量,
N
是重复的数量。不过,LINQ倾向于使用更多内存,因此对于高
N
s,最好使用循环。目前N是3或4。我将尝试LINQ方法,谢谢。我读过一些关于PLINQ的书,但还没有用过。如果同时调用
GetDict()
,PLINQ可能会更快。我一定会试一试。