使用c#进行LINQ查找

本文关键字:查找 LINQ 进行 使用 | 更新日期: 2023-09-27 18:11:34

我有一个点数据类型的大列表和一个大小相等的双列表。大小可以在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,我需要为单个XY查找所有相应的ZValue并应用统计数据。XYPairZValue匹配的索引。是否有可能使用LINQ查找来有效地实现这一目标,而不是像下面这样得到内存不足的预期错误?

目前我是这样做的:

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

使用c#进行LINQ查找

为什么需要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

如果你做了这样的事情呢?

收集你的分数…

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

我不知道性能/内存特性是什么,但我认为它确实提供了你想要的功能。

我发现一些文章有助于形成这个答案:

  • LINQ ToDictionary和ToLookup有什么区别

  • LINQ: tollookup vs ToDictionary

在。net 3.5中实现Zip操作符提供了一个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)。

祝你好运,希望对你有所帮助。