使用 C# 的 LINQ tolookup

发布于 2024-12-10 05:50:45 字数 1085 浏览 0 评论 0原文

我有一个巨大的点数据类型列表和一个相同大小的双列表。大小可能约为 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 对绘制为 X 和 Y 坐标。但要为单个 XY 应用标记颜色,我需要查找该单个 XY 的所有相应 ZValue 并应用统计信息。 XYPairZValue 匹配的索引。是否可以使用 LINQ tolookup 来有效地实现此目的,而不是通过执行以下操作来获得内存不足预期错误?

目前我正在这样做:

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

I have a huge list of the point datatype and an equal size of a double list. The size could be around 1000000. Both lists comes from a different class.

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......}

I need to plot unique XY pairs as X and Y co-ordinate. But to apply markercolor for the single XY, I need to lookup all the corresponding ZValue for that single XY and apply statistics. Index of XYPair and ZValue matches. Is it possible to use LINQ tolookup to achieve this efficiently rather than getting an outofmemory expection error by doing like below?

Currently I am doing it like this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

苏大泽ㄣ 2024-12-17 05:50:45

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

Why do you need LINQ? Just use a loop:

// 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
写下不归期 2024-12-17 05:50:45

如果你做了这样的事怎么办?

收集你的点...

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

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

我发现一些文章有助于制定此答案:

在 .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)。

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

What if you did something like this?

Gather your points...

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

Use Zip to build a new list containing (Point, Z) pairs, then convert the resulting sequence to a lookup (similar to a dictionary of groups), keyed by the Point value.

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

I don't know what the performance/memory characteristics will be, but I think that it does give the functionality you are after.

Some articles I found helpful in formulating this answer:

Implementing the Zip Operator in .NET 3.5 provides an implementation of Zip that you can use...

As I state in my comment below, the performance seems fine on my machine, so my machine might be faster, my data might not be distributed the same as yours, or what I consider "fine" you might consider "slow". Having said that, I am adding some code that might be performe better than your version (or might not). If this doesn't help enough, I don't know what else to add. Also, in your original question you say that you run out of memory. Does that still happen with my suggested code?

My rewrite of your code:

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

Note that I have not tested the processing code above. I hope that it works, and I hope that it does the equivalent work that you were doing in your original code. I don't have any particular expectations that this will be "fast" or not. The main goal in my code is to minimize the number of times that data is copied (typically by calls to ToList).

Good luck, I hope this helped.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文