在IList <idictionary <string,double =“”>&gt; </idictionary <string,>中为每个字符串构建中位数

时间:2010-04-29 10:28:54

标签: c# linq

实际上我有一点脑弯曲,而且找不到合适的方向让它起作用:

给定是IList<IDictionary<string, double>>并按如下方式填写:

Name|Value
----+-----
"x" | 3.8
"y" | 4.2
"z" | 1.5
----+-----
"x" | 7.2
"y" | 2.9
"z" | 1.3
----+-----
... | ...

为了用一些随机数据来填充,我使用了以下方法:

var list = CreateRandomPoints(new string[] { "x", "y", "z" }, 20);

这将如下工作:

private IList<IDictionary<string, double>> CreateRandomPoints(string[] variableNames, int count)
{
    var list = new List<IDictionary<string, double>>(count);
    list.AddRange(CreateRandomPoints(variableNames).Take(count));

    return list;
}

private IEnumerable<IDictionary<string, double>> CreateRandomPoints(string[] variableNames)
{
    while (true)
        yield return CreateRandomLine(variableNames);
}

private IDictionary<string, double> CreateRandomLine(string[] variableNames)
{
    var dict = new Dictionary<string, double>(variableNames.Length);

    foreach (var variable in variableNames)
    {
        dict.Add(variable, _Rand.NextDouble() * 10);
    }

    return dict;
}

另外我可以说已经确保列表中的每个词典包含相同的键(但是从列表中列出名称和键的数量可以更改)。

这就是我得到的。现在我需要的东西:

我想获得所有词典中每个键的中位数(或任何其他数学聚合操作),以便我的调用函数看起来像:

IDictionary<string, double> GetMedianOfRows(this IList<IDictionary<string, double>> list)

最好的做法是将某种聚合操作作为函数的参数,使其更通用(不知道func是否具有正确的参数,但应该想象我想做什么):

private IDictionary<string, double> Aggregate(this IList<IDictionary<string, double>> list, Func<IEnumerable<double>, double> aggregator)

此外,我最大的问题是在列表中执行单次迭代的工作,因为如果在列表中有20个变量,其中包含1000个值,我不喜欢迭代20次名单。相反,我会在列表上进行一次并一次计算所有20个变量(这样做的最大好处就是在后面的步骤中将其用作IEnumerable<T>列表的任何部分。) / p>

所以这是我已经得到的代码:

public static IDictionary<string, double> GetMedianOfRows(this IList<IDictionary<string, double>> list)
{
    //Check of parameters is left out!

    //Get first item for initialization of result dictionary
    var firstItem = list[0];

    //Create result dictionary and fill in variable names
    var dict = new Dictionary<string, double>(firstItem.Count);

    //Iterate over the whole list
    foreach (IDictionary<string, double> row in list)
    {
        //Iterate over each key/value pair within the list
        foreach (var kvp in row)
        {
            //How to determine median of all values?
        }
    }

    return dict;
}

以下是对the Median的一点解释。

解决方案

感谢dtb的扩展方法。这是我所缺少的部分。

有了它,我们现在可以做如下漂亮的陈述:

var result0 = list.Cast<IEnumerable<KeyValuePair<string, double>>>()
                  .Transpose()
                  .ToDictionary(column => column.First().Key,
                                column => column.Select(kvp => kvp.Value)
                                                .Sum());

var result1 = list.Cast<IEnumerable<KeyValuePair<string, double>>>()
                  .Transpose()
                  .ToDictionary(column => column.First().Key,
                                          //Performing my own function on the IEnumerable<double>
                                column => GetSumOfElements(column.Select(kvp => kvp.Value)));

private double GetSumOfElements(IEnumerable<double> elements)
{
    double result = 0;

    foreach (var element in elements)
    {
        result += element;
    }

    return result;
}

1 个答案:

答案 0 :(得分:1)

var list = CreateRandomPoints(new string[] { "x", "y", "z" }, 20);

var result = list.Cast<IEnumerable<KeyValuePair<string, double>>>()
                 .Transpose()
                 .ToDictionary(row => row.First().Key,
                               row => row.Select(kvp => kvp.Value).Median());

来自hereTranspose和来自hereMedian

这是对transpose of a matrix的一点解释。 : - )