gacar Ответов: 2

Каков самый быстрый способ вычитания элементов длинного массива?


У меня долгое время
Dim LongArray As Long() = {1595741111714190885, 2681354977222731062, 3897343441765742102, 1813043105221908777, 2970433094069856569, ...} 

Я хочу вычесть каждый пункт из следующего пункта.
Dim DiffArray As New List(Of Long)

For i As Integer = 0 To LongArray.Count - 1
      Dim Diff As Long = LongArray(i + 1) - LongArray(i)
      DiffArray.Add(Diff)
Next

Но это слишком медленно.

Что я уже пробовал:

НА СЛЕДУЮЩИЙ
Dim LongArray As Long() = {1595741111714190885, 2681354977222731062, 3897343441765742102, 1813043105221908777, 2970433094069856569}

Dim DiffArray As New List(Of Long)

For i As Integer = 0 To LongArray.Count - 1
      Dim Diff As Long = LongArray(i + 1) - LongArray(i)
      DiffArray.Add(Diff)
Next

LINQ
Dim DiffArray2 = (From x In LongArray Let nextindex = LongArray.ToList.IndexOf(x) + 1 Let nextelement = LongArray.ToList.ElementAt(If(nextindex = LongArray.ToList.Count, nextindex - 1, nextindex)) Select nextelement - x).ToList()

Patrice T

Что именно ты пытаешься сделать ?
Ваш код выполняет не только вычитание.

2 Ответов

Рейтинг:
9

Dave Kreskowiak

Списки будут немного замедлять процесс.

Самое быстрое, что вы собираетесь сделать, это запустить цикл Fox/Next, но сначала предварительно распределите свой DiffArray до размера, необходимого для хранения всех значений, которые вы собираетесь вычислить, который должен быть размером вашего LongArray - 1.

Dim DiffArray(LongArray.Count - 1) As Long

For i As Integer = 0 To LongArray.Count - 1
    Dim Diff As Long = LongArray(i + 1) - LongArray(i)
    DiffArray(i) = Diff
Next


Jochen Arndt

Должно быть
For i As Integer = 0 To DiffArray.Count - 1
или
For i As Integer = 0 To LongArray.Count - 2

В любом случае я возражал против 1 голоса.

gacar

Да, конечно.

gacar

Дэйв Кресковяк, такс для решения проблемы. Да, теперь очень быстро.

Dave Kreskowiak

Спасибо! Было уже поздно, и мой мозг отключился. :)

Рейтинг:
14

Graeme_Grant

Дэйв попал в точку... Чтобы дать вам пример, я запустил тест на 10 000 элементов, используя 1. Код Дейва; 2. версию Linq; 3. версию PLinq. Ниже приведен код:

<Benchmark(Baseline:=True)>
Public Sub Execute()
    Dim diffArray = New Long(maxSize - 1 - 1) {}

    For i As Integer = 0 To diffArray.Length - 1
        diffArray(i) = LongArray(i + 1) - LongArray(i)
    Next
End Sub

<Benchmark>
Public Sub ExecuteLinq()
    Dim diffArray As Long() = LongArray.Skip(1).[Select](Function(x, i) LongArray(i) - x).ToArray()
End Sub

<Benchmark>
Public Sub ExecutePLinq()
    Dim diffArray As Long() = LongArray.Skip(1).[Select](Function(x, i) LongArray(i) - x).AsParallel().AsOrdered().ToArray()
End Sub

А вот и результаты бенчмарка:
// * Summary *

BenchmarkDotNet=v0.11.1, OS=Windows 10.0.17134.228 (1803/April2018Update/Redstone4)
Intel Core i7-4980HQ CPU 2.80GHz (Haswell), 1 CPU, 8 logical and 4 physical cores
  [Host]     : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.3132.0
  DefaultJob : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.3132.0


       Method |        Mean |     Error |    StdDev | Scaled | ScaledSD |
------------- |------------:|----------:|----------:|-------:|---------:|
      Execute |    22.02 us | 0.2142 us | 0.2003 us |   1.00 |     0.00 |
  ExecuteLinq |   297.39 us | 1.6327 us | 1.5272 us |  13.51 |     0.14 |
 ExecutePLinq | 1,210.37 us | 6.4961 us | 5.7586 us |  54.98 |     0.54 |

// * Legends *
  Mean     : Arithmetic mean of all measurements
  Error    : Half of 99.9% confidence interval
  StdDev   : Standard deviation of all measurements
  Scaled   : Mean(CurrentBenchmark) / Mean(BaselineBenchmark)
  ScaledSD : Standard deviation of ratio of distribution of [CurrentBenchmark] and [BaselineBenchmark]
  1 us     : 1 Microsecond (0.000001 sec)

Надеюсь, это поможет! :)


gacar

Graeme_Grant, благодарность за решение. Ваше первое решение самое быстрое. А также Спасибо за linq solutions.