I'm back with improved version of previous Deca dimensional array sort function. This one is not just 10 dimension limited. It could be extended to unlimited number of dimensions by simply adding rows using same logic under each Select case
iteration. A limit still exists, which is it's the memory limit.
Compared with previous code, there are a number of advantages:
A number of complementary functions within the same function, extendable with other functions without the need to repeat code (
fillZero
,fillSequence
,clearArray
, etc).Helper functions could be used independently for building various other functions.
This function is considerably shorter then previous one.
Does anyone have any improvement ideas? The next step will be adding a filter array function.
Option Explicit
Public Function SortArray(ByRef arr As Variant, ByVal selPoint As Variant, ByRef selDim As Integer, Optional ByRef ascend As Boolean = True) As Variant
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Multi Dimensional Ascending and Descending Sort Array Function
'Inputs:
'1) arr = one to 10 dimensional symmetrical array
'2) selPoint = selected point index as string e.g. "arr(1,15,4)" or just "(1,15,4)"
'3) selDim = selected dimension, integer from 1 to 10
'4) ascend = Optional ascending or descending direction (default = ascending)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim seq As Variant, seqArr As Variant, idx As Variant, s As Variant, d As Variant
Dim i As Integer, arrDim As Integer
Dim LB As Long, UB As Long
LB = LBound(arr, selDim)
UB = UBound(arr, selDim)
ReDim seqArr(UB)
On Error Resume Next
Do
arrDim = arrDim + 1
seq = UBound(arr, arrDim)
Loop Until Err.Number <> 0
arrDim = arrDim - 1
On Error GoTo 0
ReDim seq(UB)
' For i = LB To UB
' seq(i) = i
' Next i
' replaced with
seq = ArrayAction(seq, , "fillSeries")
s = Split(Split(selPoint, "(")(1), ")")(0)
s = Split(s, ",")
ReDim d(arrDim - 1)
' For i = 0 To arrDim - 1
' d(i) = s(i)
' Next i
' replaced with
d = ArrayAction(d, , "fillSequence", s)
For i = LB To UB
d(selDim - 1) = i
Select Case arrDim
Case Is = 1
seqArr(i) = arr(d(0))
Case Is = 2
seqArr(i) = arr(d(0), d(1))
Case Is = 3
seqArr(i) = arr(d(0), d(1), d(2))
Case Is = 4
seqArr(i) = arr(d(0), d(1), d(2), d(3))
Case Is = 5
seqArr(i) = arr(d(0), d(1), d(2), d(3), d(4))
Case Is = 6
seqArr(i) = arr(d(0), d(1), d(2), d(3), d(4), d(5))
Case Is = 7
seqArr(i) = arr(d(0), d(1), d(2), d(3), d(4), d(5), d(6))
Case Is = 8
seqArr(i) = arr(d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7))
Case Is = 9
seqArr(i) = arr(d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7), d(8))
Case Is = 10
seqArr(i) = arr(d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7), d(8), d(9))
End Select
Next i
idx = ArrayAction(arr, , "clearArray")
seq = SortSeq(seqArr, seq, LB, UB, ascend)
idx = ArrayAction(arr, idx, "sortIndex", seq, selDim)
SortArray = ArrayAction(arr, idx, "sortArray")
End Function
Private Function ArrayAction(ByVal arr As Variant, _
Optional ByRef idx As Variant, _
Optional ByRef ActionTag As String = "index", _
Optional ByRef seq As Variant, _
Optional ByRef sortDim As Integer = 1, _
Optional ByRef del As String = ",") As Variant
Dim s As Variant, d As Variant, rArr As Variant, wArr As Variant, oArr As Variant
Dim i As Integer, arrDim As Integer, selDim As Integer
oArr = arr
On Error Resume Next
Do
arrDim = arrDim + 1
d = UBound(arr, arrDim)
Loop Until Err.Number <> 0
arrDim = arrDim - 1
On Error GoTo 0
ReDim d(arrDim - 1)
For i = 0 To arrDim - 1
d(i) = 0
Next i
For selDim = arrDim To 1 Step -1
If selDim <> arrDim Then
If d(selDim - 1) = UBound(arr, selDim) Then
On Error Resume Next
Do
d(selDim - 1) = LBound(arr, selDim)
selDim = selDim - 1
Loop Until d(selDim - 1) <> UBound(arr, selDim)
On Error GoTo 0
End If
If selDim = 0 Then Exit For
d(selDim - 1) = d(selDim - 1) + 1
selDim = arrDim
End If
For i = LBound(arr, selDim) To UBound(arr, selDim)
d(selDim - 1) = i
'read index
If Not IsMissing(idx) Then
Select Case arrDim
Case Is = 1
rArr = idx(d(0))
Case Is = 2
rArr = idx(d(0), d(1))
Case Is = 3
rArr = idx(d(0), d(1), d(2))
Case Is = 4
rArr = idx(d(0), d(1), d(2), d(3))
Case Is = 5
rArr = idx(d(0), d(1), d(2), d(3), d(4))
Case Is = 6
rArr = idx(d(0), d(1), d(2), d(3), d(4), d(5))
Case Is = 7
rArr = idx(d(0), d(1), d(2), d(3), d(4), d(5), d(6))
Case Is = 8
rArr = idx(d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7))
Case Is = 9
rArr = idx(d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7), d(8))
Case Is = 10
rArr = idx(d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7), d(8), d(9))
End Select
End If
s = Split(rArr, del)
'read target cell based on index
If rArr <> "" Then
Select Case arrDim
Case Is = 1
rArr = oArr(s(0))
Case Is = 2
rArr = oArr(s(0), s(1))
Case Is = 3
rArr = oArr(s(0), s(1), s(2))
Case Is = 4
rArr = oArr(s(0), s(1), s(2), s(3))
Case Is = 5
rArr = oArr(s(0), s(1), s(2), s(3), s(4))
Case Is = 6
rArr = oArr(s(0), s(1), s(2), s(3), s(4), s(5))
Case Is = 7
rArr = oArr(s(0), s(1), s(2), s(3), s(4), s(5), s(6))
Case Is = 8
rArr = oArr(s(0), s(1), s(2), s(3), s(4), s(5), s(6), s(7))
Case Is = 9
rArr = oArr(s(0), s(1), s(2), s(3), s(4), s(5), s(6), s(7), s(8))
Case Is = 10
rArr = oArr(s(0), s(1), s(2), s(3), s(4), s(5), s(6), s(7), s(8), s(9))
End Select
End If
'modify result based on requested action
wArr = ArrayFunction(ActionTag, rArr, i, d, seq, sortDim, del)
'write back calculated value
Select Case arrDim
Case Is = 1
arr(d(0)) = wArr
Case Is = 2
arr(d(0), d(1)) = wArr
Case Is = 3
arr(d(0), d(1), d(2)) = wArr
Case Is = 4
arr(d(0), d(1), d(2), d(3)) = wArr
Case Is = 5
arr(d(0), d(1), d(2), d(3), d(4)) = wArr
Case Is = 6
arr(d(0), d(1), d(2), d(3), d(4), d(5)) = wArr
Case Is = 7
arr(d(0), d(1), d(2), d(3), d(4), d(5), d(6)) = wArr
Case Is = 8
arr(d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7)) = wArr
Case Is = 9
arr(d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7), d(8)) = wArr
Case Is = 10
arr(d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7), d(8), d(9)) = wArr
End Select
Next i
Next selDim
ArrayAction = arr
End Function
Private Function ArrayFunction(ByRef ActionTag As String, _
ByRef rArr As Variant, _
ByRef i As Integer, _
ByVal d As Variant, _
ByRef seq As Variant, _
ByRef sortDim As Integer, _
ByRef del As String) As Variant
Select Case ActionTag
Case Is = "sortIndex"
d(sortDim - 1) = seq(d(sortDim - 1))
Case Is = "fillZero"
ArrayFunction = 0
Exit Function
Case Is = "fillSeries"
ArrayFunction = i
Exit Function
Case Is = "fillSequence"
ArrayFunction = seq(i)
Exit Function
Case Is = "sortArray"
ArrayFunction = rArr
Exit Function
Case Is = "clearArray"
ArrayFunction = Empty
Exit Function
End Select
Select Case UBound(d)
Case Is = 0
ArrayFunction = d(0)
Case Is = 1
ArrayFunction = d(0) & del & d(1)
Case Is = 2
ArrayFunction = d(0) & del & d(1) & del & d(2)
Case Is = 3
ArrayFunction = d(0) & del & d(1) & del & d(2) & del & d(3)
Case Is = 4
ArrayFunction = d(0) & del & d(1) & del & d(2) & del & d(3) & del & d(4)
Case Is = 5
ArrayFunction = d(0) & del & d(1) & del & d(2) & del & d(3) & del & d(4) & del & d(5)
Case Is = 6
ArrayFunction = d(0) & del & d(1) & del & d(2) & del & d(3) & del & d(4) & del & d(5) & del & d(6)
Case Is = 7
ArrayFunction = d(0) & del & d(1) & del & d(2) & del & d(3) & del & d(4) & del & d(5) & del & d(6) & del & d(7)
Case Is = 8
ArrayFunction = d(0) & del & d(1) & del & d(2) & del & d(3) & del & d(4) & del & d(5) & del & d(6) & del & d(7) & del & d(8)
Case Is = 9
ArrayFunction = d(0) & del & d(1) & del & d(2) & del & d(3) & del & d(4) & del & d(5) & del & d(6) & del & d(7) & del & d(8) & del & d(9)
End Select
End Function
Private Function SortSeq(ByRef iArr As Variant, ByRef sArr As Variant, ByRef iDnRow As Long, ByRef iUpRow As Long, Optional ByRef ascend As Boolean = True) As Variant
Dim oArr As Variant, vArr As Variant
Dim vDnRow As Long, vUpRow As Long
vDnRow = iDnRow
vUpRow = iUpRow
oArr = iArr((iDnRow + iUpRow) \ 2)
While (vDnRow <= vUpRow)
If ascend = True Then
While (iArr(vDnRow) < oArr And vDnRow < iUpRow)
vDnRow = vDnRow + 1
Wend
While (oArr < iArr(vUpRow) And vUpRow > iDnRow)
vUpRow = vUpRow - 1
Wend
Else
While (iArr(vDnRow) > oArr And vDnRow < iUpRow)
vDnRow = vDnRow + 1
Wend
While (oArr > iArr(vUpRow) And vUpRow > iDnRow)
vUpRow = vUpRow - 1
Wend
End If
If (vDnRow <= vUpRow) Then
vArr = iArr(vDnRow)
iArr(vDnRow) = iArr(vUpRow)
iArr(vUpRow) = vArr
vArr = sArr(vDnRow)
sArr(vDnRow) = sArr(vUpRow)
sArr(vUpRow) = vArr
vDnRow = vDnRow + 1
vUpRow = vUpRow - 1
End If
Wend
If (iDnRow < vUpRow) Then SortSeq iArr, sArr, iDnRow, vUpRow, ascend
If (vDnRow < iUpRow) Then SortSeq iArr, sArr, vDnRow, iUpRow, ascend
SortSeq = sArr
End Function
Simple test sub:
Sub testSortArray()
Dim arr As Variant, indexArr As Variant, s As Variant
ReDim arr(1, 1, 5)
arr(0, 0, 0) = 0
arr(0, 0, 1) = 1
arr(0, 0, 2) = 2
arr(0, 0, 3) = 3
arr(0, 0, 4) = 4
arr(0, 0, 5) = 5
arr(0, 1, 0) = 10
arr(0, 1, 1) = 11
arr(0, 1, 2) = 12
arr(0, 1, 3) = 13
arr(0, 1, 4) = 14
arr(0, 1, 5) = 15
arr(1, 0, 0) = 100
arr(1, 0, 1) = 101
arr(1, 0, 2) = 102
arr(1, 0, 3) = 103
arr(1, 0, 4) = 104
arr(1, 0, 5) = 105
arr(1, 1, 0) = 110
arr(1, 1, 1) = 111
arr(1, 1, 2) = 112
arr(1, 1, 3) = 113
arr(1, 1, 4) = 114
arr(1, 1, 5) = 115
arr = SortArray(arr, "(1,1,0)", 3, False)
indexArr = ArrayAction(arr)
End Sub