.NET Framework позволяет легко делать параллельную агрегацию, но в соответствии с the documentation, она работает только для коммутативных операций, то есть операция, при которой е (х, у) = е (у , х):Есть ли простой способ сделать параллельную агрегацию с некоммутативной операцией?
реализация .NET из параллельного шаблона Aggregation также ожидает операции коммутативным.
Я хочу объединить строковые значения с помощью конкатенации, то есть некоммутативной операции. Последовательный подход выглядит следующим образом:
var result = string.Concat(sequence.Select(this.LongOperation));
так что если this.LongOperation
возвращает последовательно Hello
, World
и !
, конечный результат HelloWorld!
.
Если я использую параллельную агрегацию, результат может быть HelloWorld
, но и World!Hello
, !HelloWorld
и т.д.
Обходной бы сделать что-то похожее на:
var result = sequence
.AsParallel()
.Select((v, i) => new { Index = i, Value = v })
.Select(c => new { Index = c.Index, Value = this.LongOperation(c.Value))
.OrderBy(c => c.Index)
.Aggregate(seed: string.Empty, func: (prev, current) => prev + current);
с (неважно, в моем конкретном случае) недостаток, что вся последовательность будет оцениваться на этапе OrderBy
в любом случае, не дожидаясь агрегации. Другой способ написать это:
var parts = sequence
.AsParallel()
.Select((v, i) => new { Index = i, Value = v })
.Select(c => new { Index = c.Index, Value = this.LongOperation(c.Value))
.OrderBy(c => c.Index)
.Select(c => c.Value);
var result = string.Concat(parts);
Am Я ожидал, чтобы сделать это, или есть более простой способ сделать вещь?
@downvoter - Поучительно объяснять? –
Этот ответ совершенно неверен. Агрегат - это метод для Enumerable. Рассмотрим случай, когда тип аккумулятора отличается от типа элементов. Вам понадобится алгоритм сокращения карты. – Aron
@Aron - Это именно то, что он делает с «Агрегатом», Он делает сокращение. Он также хочет сохранить порядок, согласно указанному вопросу. Это именно то, что он делает в своем примере. i –