实际上我有一点脑弯曲,而且找不到合适的方向让它起作用:
给定是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;
}
答案 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());
来自here的Transpose
和来自here的Median
。
这是对transpose of a matrix的一点解释。 : - )