道歉,如果我错过了一些非常基本的东西。
对于给定的晶格数组,其中晶格值代表其桶的最小值,对值数组进行分组的最佳方法是什么。
e.g。
double[] lattice = { 2.3, 2.8, 4.1, 4.7 };
double[] values = { 2.35, 2.4, 2.6, 3, 3.8, 4.5, 5.0, 8.1 };
GroupByLattice(values, lattice);
使GroupByLattice返回如下所示的IGroupings:
2.3 : { 2.35, 2.4, 2.6 }
2.8 : { 3, 3.8 }
4.1 : { 4.5 }
4.7 : { 5.0, 8.1 }
修改
对于LINQ查询,我已经足够绿了,这是我能做到的最好的:
values.GroupBy( curr => lattice.First( lat => curr > lat) )
问题:
死后解决方案和结果:
Dmitry Bychenko提供了一个很好的答案,我只是想为将来可能会遇到这个答案的人提供一些跟进。我原本试图解决:How can I simplify a huge dataset for plotting?
对于初学者来说,我的第一次尝试实际上非常接近。我的格子已订购,我只需将.First( ... )
更改为.Last( ... )
即
values.GroupBy( curr => lattice.Last( lat => curr > lat) )
这一切都很好,但很好奇Dmitry的解决方案会有多好。我用随机的10000个双打测试它,格子间距为0.25。 (我从Dmitry的解决方案中取出.Select(...)
转换以保持公平)
平均20次运行吐出结果:
Mine: 602ms
Dmitrys: 3ms
呃......哇!这速度提高了200倍。 200x!我必须运行几次并在调试器中进行检查,以确保LINQ语句在时间戳之前进行评估(Trusty .ToArray()
以进行救援)。我现在要说出来,任何想要完成同样任务的人都应该使用这种方法
答案 0 :(得分:5)
假设lattice
已排序(使用Array.Sort(lattice)
对数组进行排序很容易),您可以使用Array.BinarySearch
:
double[] lattice = { 2.3, 2.8, 4.1, 4.7 };
double[] values = { 2.35, 2.4, 2.6, 3, 3.8, 4.5, 5.0, 8.1 };
var result = values
.GroupBy(item => {
int index = Array.BinarySearch(lattice, item);
return index >= 0 ? lattice[index] : lattice[~index - 1];
})
.Select(chunk => String.Format("{0} : [{1}]",
chunk.Key, String.Join(", ", chunk)));
测试
Console.Write(String.Join(Environment.NewLine, result));
结果
2.3 : [2.35, 2.4, 2.6]
2.8 : [3, 3.8]
4.1 : [4.5]
4.7 : [5, 8.1]
答案 1 :(得分:0)
如果您需要更快,如果两个数组都已排序,您只能迭代一次数组:
double[] lattice = { 2.3, 2.8, 4.1, 4.7 };
double[] values = { 2.35, 2.4, 2.6, 3, 3.8, 4.5, 5.0, 8.1 };
var result = new List<double>[lattice.Length]; // array of lists
for (int l = lattice.Length - 1, v = values.Length - 1; l >= 0; l--) // starts from last elements
{
result[l] = new List<double>(values.Length / lattice.Length * 2); // optional initial capacity of the list
for (; v >= 0 && values[v] >= lattice[l]; v--)
{
result[l].Insert(0, values[v]);
}
}