LINQ tolookup с использованием C # - PullRequest
3 голосов
/ 17 октября 2011

У меня огромный список точечных типов данных и одинаковый размер двойного списка. Размер может быть около 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. Но чтобы применить маркерcolor для единственного XY, мне нужно найти все соответствующие ZValue для этого единственного XY и применить статистику. Индекс XYPair и ZValue совпадений. Можно ли использовать 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);
    }
}

Ответы [ 2 ]

2 голосов
/ 17 октября 2011

Что, если вы сделали что-то подобное?

Соберите свои очки ...

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

Я не знаюкакими будут характеристики производительности / памяти, но я думаю, что это даст вам те функции, которые вам нужны.

Некоторые статьи, которые я нашел полезными при формулировании этого ответа:

Реализация Zip-оператора в .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).

Удачи, надеюсь, это помогло.

2 голосов
/ 17 октября 2011

Зачем вам нужен 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...