Существует несколько способов решения этой проблемы с использованием подхода на основе linq.
Если вы используете VB.NET 4.0, вы можете использовать многострочные лямбда-выражения, которые дадут вам наиболее близкое решениек тому, что вы пытались:
Dim runningTotal = 0
Dim getRunningTotal As Func(Of Integer, Integer) = Function(n)
runningTotal += n
Return runningTotal
End Function
Dim results2 =
From v In results1
Select New With { .num = v.green, .running_total = getRunningTotal(v.green) }
Гвоздем этого подхода является то, что если вы оцениваете запрос result2
более одного раза, вы сложите промежуточный итог (т.е. продолжите считать с прошлого раза),В любом случае, то же самое произошло бы в вашем коде.
В C # я бы создал метод расширения, использующий для этого итераторы, но на данный момент VB.NET не поддерживает функции итераторов, поэтому мы должны выбратьнекоторые более забавные способы сделать это.
Первый использует методы расширения Aggregate
& Zip
:
Dim results2 =
results1.Zip(
results1.Aggregate(
New Integer() { },
Function(tt, t) _
tt.Concat(New Integer() { tt.LastOrDefault() + t.green }).ToArray()
),
Function (r1, rt) New With { .num = r1.green, .running_total = rt }
)
Да, это работает, но не слишком эффективнотак как он должен создавать последовательные промежуточные массивы для каждого элемента в исходной коллекции.
Последний подход заключается в использовании метода расширения Scan
, доступного из библиотеки System.Interactive
, созданной командой Rx в Microsoft.Scan
работает как Aggregate
, но выдает промежуточные значения автоматически и, следовательно, намного эффективнее.
Dim results2 =
results1.Scan(
New With { .num = 0, .running_total = 0 },
Function (tt, t) _
New With { .num = t.green, .running_total = tt.running_total + t.green }
)
Или:
Dim results2 =
results1.Zip(
results1.Scan(0, Function(tt, t) tt + t.green),
Function (r1, rt) New With { .num = r1.green, .running_total = rt }
)
Просто, да?