事实上,我有点脑筋急转弯,只是找不到正确的方向让它工作:
给定是一个
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>
列表的任何部分)。
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
.
解决方案
有了它,我们现在可以做这样美丽的陈述:
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;
}