由任意格子

时间:2016-07-25 18:56:56

标签: c# linq

道歉,如果我错过了一些非常基本的东西。

对于给定的晶格数组,其中晶格值代表其桶的最小值,对值数组进行分组的最佳方法是什么。

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) )

问题:

  • 一切都在第一桶中结束 - 我可以理解为什么(当然第一个桶满足每个后面的情况)但是我很难绕过这些就地操作来获得断言我真的想要。
  • 我怀疑在LINQ查询中有一个LINQ查询不会非常高效

死后解决方案和结果:

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()以进行救援)。我现在要说出来,任何想要完成同样任务的人都应该使用这种方法

2 个答案:

答案 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]);
    }
}