I put random values into range A1:F50000
.
Here is an example for 4 different ways to calculate the sum of each row:
Formula: 211,6254 'Fill formula and replace with values (range)
LoopCells: 3909,2864 'Calculate each cell value (loop)
LoopWsFunc: 3103,0727 'Calculate each cell with worksheet function (loop)
LoopArray: 159,9878 'Calculate in array (read/write) at once
So actually using VBA and arrays is the fastest way (in this test case). But it might depend on the formula you use and how many data there is in the sheet. To be sure to use the fastest method for your specific case, code more than one way and test which one is faster.
Here is the code I used
Option Explicit
Public Sub TestFormula()
Dim t As New cTimer
t.StartCounter
With Range("H1:H50000")
.Formula = "=SUM(A1:F1)" 'write formula to all cells
.Value = .Value 'replace formula by values
End With
Debug.Print "Formula:", t.TimeElapsed
End Sub
Public Sub TestLoopCells()
Dim t As New cTimer
t.StartCounter
Dim iRow As Long
For iRow = 1 To 50000 'calculate each cell by looping
Cells(iRow, "H").Value = Cells(iRow, 1).Value + Cells(iRow, 2).Value + Cells(iRow, 3).Value + Cells(iRow, 4).Value + Cells(iRow, 5).Value + Cells(iRow, 6).Value
Next iRow
Debug.Print "LoopCells:", t.TimeElapsed
End Sub
Public Sub TestLoopWsFunc()
Dim t As New cTimer
t.StartCounter
Dim iRow As Long
For iRow = 1 To 50000 'Calculate each cell with sum function by looping
Cells(iRow, "H").Value = WorksheetFunction.Sum(Range("A" & iRow & ":G" & iRow))
Next iRow
Debug.Print "LoopWsFunc:", t.TimeElapsed
End Sub
Public Sub TestLoopArray()
Dim t As New cTimer
t.StartCounter
Dim InputArr() As Variant 'read data into array
InputArr = Range("A1:F50000").Value
ReDim OutputArr(1 To 50000, 1 To 1) As Variant 'generate output array
Dim iRow As Long
For iRow = 1 To 50000 'sum within the array
OutputArr(iRow, 1) = InputArr(iRow, 1) + InputArr(iRow, 2) + InputArr(iRow, 3) + InputArr(iRow, 4) + InputArr(iRow, 5)
Next iRow
Range("H1:H50000").Value = OutputArr 'write the result from the array to the cells
Debug.Print "LoopArray:", t.TimeElapsed
End Sub
Class Module cTimer
for performance testing
Option Explicit
Private Type LARGE_INTEGER
lowpart As Long
highpart As Long
End Type
Private Declare PtrSafe Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As LARGE_INTEGER) As Long
Private Declare PtrSafe Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As LARGE_INTEGER) As Long
Private m_CounterStart As LARGE_INTEGER
Private m_CounterEnd As LARGE_INTEGER
Private m_crFrequency As Double
Private Const TWO_32 = 4294967296# ' = 256# * 256# * 256# * 256#
Private Function LI2Double(LI As LARGE_INTEGER) As Double
Dim Low As Double
Low = LI.lowpart
If Low < 0 Then
Low = Low + TWO_32
End If
LI2Double = LI.highpart * TWO_32 + Low
End Function
Private Sub Class_Initialize()
Dim PerfFrequency As LARGE_INTEGER
QueryPerformanceFrequency PerfFrequency
m_crFrequency = LI2Double(PerfFrequency)
End Sub
Public Sub StartCounter()
QueryPerformanceCounter m_CounterStart
End Sub
Property Get TimeElapsed() As Double
Dim crStart As Double
Dim crStop As Double
QueryPerformanceCounter m_CounterEnd
crStart = LI2Double(m_CounterStart)
crStop = LI2Double(m_CounterEnd)
TimeElapsed = 1000# * (crStop - crStart) / m_crFrequency
End Property
Source: VBA Implementation of QueryPerformanceCounter