使用C#的LINQ tolookup

时间:2011-10-17 15:18:28

标签: c# linq lookup

我有一个庞大的点数据类型列表和一个相同大小的双列表。大小可能在1000000左右。两个列表都来自不同的类。

List<Point> XYPair;  E.g. { (10,10),(10,10).......(20,20),(20,20).....}
List<double> ZValue; E.g. { 1.5, 1.6, .............7.8,8.7......}

我需要将唯一XY对绘制为XY坐标。但是要为单XY应用markercolor,我需要查找该单ZValue的所有相应XY并应用统计信息。 XYPairZValue的索引匹配。是否可以使用 LINQ tolookup来有效地实现这一点,而不是通过如下所示获得outofmemory expction错误?

目前我这样做:

GroupedPlotValues = XYLocation
    .Select(bv => bv.ElementAt(0))
    .Select((p, i) => new { Item1 = p, Item2 = i })
    .GroupBy(tp => tp.Item1, tp => tp.Item2)
    .ToDictionary(gr => gr.Key, gr => gr.ToList());


foreach (var item in GroupedPlotValues)
{
    var matched = item.Value.Intersect(MatchingIndexes).ToList();
    if (matched.Count != 0)
    {
        chart1.Series[0].Points.AddXY(item.Key.X, item.Key.Y);
        var singleZGroup = item.Value.Select(y => ZColumn[y]).ToList();
        ApplyStatistics(singleZGroup);
    }
}

2 个答案:

答案 0 :(得分:2)

为什么需要LINQ?只需使用循环:

// Prepare the dictionary
Dictionary<Key, List<double>> dic = new Dictionary<Key, List<double>>();
for (int i =0; i< XYPair.Count; i++){
    // Create the key
    // Put ZValue[i] values in dictionary list element
}

// Use the Dictionary:

// Loop around dic keys
// If matched, apply statistics

答案 1 :(得分:2)

如果你这样做会怎么样?

收集你的观点......

var XY = new List<Point>()
{
  { new Point(0, 0) },
  { new Point(10, 20) },
  { new Point(15, 5)},
  { new Point(0,0)},
  { new Point(10,20)}
};

收集你的Z值......

var Z = new List<double>() { 0, 10, 20, 30, 40 };

使用Zip构建包含(Point,Z)对的新列表,然后将结果序列转换为查找(类似于组字典),由Point值键入。

var lookup = XY.Zip(Z, (xy, z) => new { Point = xy, Z = z }).ToLookup(k => k.Point, v => v.Z);

我不知道性能/内存特性是什么,但我认为它确实提供了您所追求的功能。

我发现有些文章有助于制定这个答案:

Implementing the Zip Operator in .NET 3.5 提供了Zip的实现,您可以使用...

正如我在下面的评论中所述,我的机器上的性能似乎很好,所以我的机器可能更快,我的数据可能不会像你的那样分配,或者我认为“好”你可能认为“慢” 。话虽如此,我正在添加一些可能比您的版本更好的代码(或者可能不是)。如果这没有用,我不知道还有什么要补充。此外,在您的原始问题中,您说您的内存不足。我建议的代码是否还会发生这种情况?

我重写了你的代码:

//Gather your position data
var XY = new List<Point>();
{
  { new Point(0, 0) },
  { new Point(10, 20) },
  { new Point(15, 5)},
  { new Point(0,0)},
  { new Point(10,20)}
};

//Gather your Z values ..
var Z = new List<double>() { 0, 10, 20, 30, 40 };

//Build the lookup
var lookup = XY.Zip(Z, (xy, z) => new { Point = xy, Z = z }).ToLookup(k => k.Point, v => v.Z);

//Process...
//foreach unique XY (the Key of the lookup)
//  Check to see if the XY is in a set of MatchingIndexes.  If not, continue.
//  Add the unique point to the chart series.
//  Get the Z values that correspond to the key (no need for ToList unless ApplyStatistics needs something more specialized than IEnumerable).
//  Apply the Z values by calling ApplyStatistics
//
foreach (g in lookup.Select(g => g.Key))
{
  var matched = MatchingIndexes.Select(i => i == g);
  if (!matched.Any()) continue;
  chart1.Series[0].Points.AddXY(g.X, g.Y);
  var singleZGroup = lookup[g];
  ApplyStatistics(singleZGroup);
}

请注意,我尚未测试上面的处理代码。我希望它有效,我希望它能完成您在原始代码中所做的同等工作。我没有任何特别的期望,这将是“快”或不。我的代码的主要目标是最小化数据复制的次数(通常通过调用ToList)。

祝你好运,我希望这会有所帮助。