Option Explicit
Private Sub S_Sort_random()
Dim rg, R, C, a
Set rg = Sheet1.Range("C4").Resize(100, 10)
a = rg.Value
VBA.Randomize
For R = 1 To UBound(a)
For C = 1 To UBound(a, 2)
a(R, C) = Int(VBA.Rnd * 4) + 1
Next
Next
rg.Value = a
Set rg = Sheet1.Range("AA5").Resize(4, 20)
a = rg.Value
For R = 1 To UBound(a)
For C = 1 To UBound(a, 2)
a(R, C) = Int(VBA.Rnd * 4) + 1
Next
Next
rg.Value = a
End Sub
Private Sub S_SortV_test()
Dim B, a(1 To 10, 1 To 3), I%, j%: I = 1
' a(i, 1) = "z": a(i, 2) = 1: a(i, 3) = 1: i = i + 1
' a(i, 1) = "z": a(i, 2) = 2: a(i, 3) = 2: i = i + 1
' a(i, 1) = "z": a(i, 2) = 2: a(i, 3) = 4: i = i + 1
' a(i, 1) = "z": a(i, 2) = 2: a(i, 3) = 5: i = i + 1
' a(i, 1) = "a": a(i, 2) = 1: a(i, 3) = 1: i = i + 1
' a(i, 1) = "a": a(i, 2) = 2: a(i, 3) = 1: i = i + 1
' a(i, 1) = "a": a(i, 2) = 5: a(i, 3) = 1: i = i + 1
' a(i, 1) = ChrW(272): a(i, 2) = 2: a(i, 3) = 1: i = i + 1
' a(i, 1) = ChrW(272): a(i, 2) = 4: a(i, 3) = 1: i = i + 1
' a(i, 1) = ChrW(272): a(i, 2) = 1: a(i, 3) = 1: i = i + 1
B = S_Sortv(Sheet1.[B4:F203].Value)
End Sub
Function S_Sortv(ByVal SortArray, Optional ByVal Columns = -1, Optional ByVal sortDescending As Boolean)
On Error GoTo E
Dim data, a(), B(), x(), w(), ww(), iw&, iww&, K&, Min&, C&, R&, I&, L&, u&, z()
Dim lb%, ub&, lb2%, ub2&, Compare As VbCompareMethod
Dim lv%, lcol&, col&, V, lines&, fline&, nb&
Dim t1$, t2$, t3$, t4$, it As Boolean
data = SortArray
GoSub I
QuickSortZV data, a, lcol, , , Compare
If u > L Then
fline = lb: lines = ub: col = Columns(L + 1): GoSub L
If iw > 0 Then
For lv = L + 1 To u
lcol = Columns(lv):
If lv < u Then
col = Columns(lv + 1)
End If
If iw > 0 Then
ww = w: iw = 0: Erase w
For iww = 1 To UBound(ww, 2)
I = ww(1, iww)
fline = 1
lines = ww(2, iww)
B = ww(3, iww)
Compare = ww(4, iww)
QuickSortZV data, B, lcol, , , Compare
GoSub L
Next
End If
Next
End If
End If
GoSub z
Exit Function
L:
K = 0
For R = fline To lines
If I > 0 Then
nb = R + I - 1
a(nb) = B(R)
Else
nb = R
End If
If lv < u Then
t1 = data(a(nb), lcol)
If K > 0 Then
If t2 <> t1 Then
If K > 1 And it Then
GoSub w
End If
GoTo l2
Else
If Not it Then
t3 = data(a(nb), col)
If t4 <> t3 Then
it = True
End If
End If
End If
Else
l2: K = 0: Min = nb: t4 = data(a(nb), col): it = False
End If
K = K + 1: GoSub fw
t2 = t1
End If
Next
If K > 1 And it Then
GoSub w
End If
Return
fw:
ReDim Preserve x(1 To K)
x(K) = a(nb)
If Compare = 0 Then
V = data(a(nb), col)
If Not IsNumeric(V) And Not IsDate(V) And V <> vbNullString Then
Compare = 1
End If
End If
Return
w:
iw = iw + 1
ReDim Preserve w(1 To 4, 1 To iw)
w(1, iw) = Min
w(2, iw) = K
w(3, iw) = x
w(4, iw) = Compare: Compare = 0
Return
I:
lb = LBound(data)
ub = UBound(data)
lb2 = LBound(data, 2)
ub2 = UBound(data, 2)
If IsNumeric(Columns) Then
If Columns < lb2 Then
ReDim z(lb2 To ub2)
For lcol = lb2 To ub2
z(lcol) = lcol
Next
Columns = z: L = lb2: u = ub2
lcol = Columns(L)
ElseIf Columns > ub2 Then
S_Sortv = data
Exit Function
Else
lcol = Columns
End If
ElseIf IsArray(Columns) Then
L = LBound(Columns)
u = UBound(Columns)
lcol = Columns(L)
Else
Exit Function
End If
ReDim a(lb To ub)
For R = lb To ub
a(R) = R
If Compare = 0 Then
V = data(R, lcol)
If Not IsNumeric(V) And Not IsDate(V) And V <> vbNullString Then
Compare = 1
End If
End If
Next
Return
z:
ReDim z(lb To ub, lb2 To ub2)
If sortDescending Then
For R = lb To ub
For C = lb2 To ub2
z(R, C) = data(a(ub - R + 1), C)
Next
Next
Else
For R = lb To ub
For C = lb2 To ub2
z(R, C) = data(a(R), C)
Next
Next
End If
S_Sortv = z
Return
E: S_Sortv = data
End Function
Private Sub QuickSortZV_test()
Debug.Print StrComp(ChrW(272), ChrW(273), 1), ChrW(272) < ChrW(273)
Debug.Print StrComp(ChrW(272), ChrW(273), 1) = 0 And ChrW(272) < ChrW(273)
End Sub
Sub QuickSortZV( _
ByVal SortArray As Variant, _
ArrayTemp(), _
Optional ByVal lngColumn& = -1, _
Optional lngMin& = -1, _
Optional lngMax& = -1, _
Optional Compare As VbCompareMethod = VbCompareMethod.vbBinaryCompare)
On Error Resume Next
Dim I&, j&, varMid, Temp
Dim lngColTemp As Long
If IsEmpty(SortArray) Then Exit Sub
If InStr(TypeName(SortArray), "()") < 1 Then Exit Sub
If lngMin = -1 Then lngMin = LBound(ArrayTemp, 1)
If lngMax = -1 Then lngMax = UBound(ArrayTemp, 1)
If lngMin >= lngMax Then Exit Sub
I = lngMin: j = lngMax
varMid = Empty: varMid = SortArray(ArrayTemp((lngMin + lngMax) \ 2), lngColumn)
If IsEmpty(varMid) Then
I = lngMax: j = lngMin
ElseIf IsNull(varMid) Then
I = lngMax: j = lngMin
ElseIf varMid = vbNullString Then
I = lngMax: j = lngMin
ElseIf VarType(varMid) = vbError Then
I = lngMax: j = lngMin
ElseIf VarType(varMid) > 17 Then
I = lngMax: j = lngMin
End If
If Compare = vbBinaryCompare Then
While I <= j
While SortArray(ArrayTemp(I), lngColumn) < varMid And I < lngMax: I = I + 1: Wend
While varMid < SortArray(ArrayTemp(j), lngColumn) And j > lngMin: j = j - 1: Wend
If I <= j Then
Swap1: Temp = ArrayTemp(I): ArrayTemp(I) = ArrayTemp(j): ArrayTemp(j) = Temp
I = I + 1: j = j - 1
End If
Wend
Else
While I <= j
While (StrComp(SortArray(ArrayTemp(I), lngColumn), varMid, 1) = -1 Or (SortArray(ArrayTemp(I), lngColumn) > varMid) And StrComp(SortArray(ArrayTemp(I), lngColumn), varMid, 1) = 0) And I < lngMax: I = I + 1: Wend
While (StrComp(varMid, SortArray(ArrayTemp(j), lngColumn), 1) = -1 Or (varMid > SortArray(ArrayTemp(j), lngColumn)) And StrComp(varMid, SortArray(ArrayTemp(j), lngColumn), 1) = 0) And j > lngMin: j = j - 1: Wend
If I <= j Then
Swap2: Temp = ArrayTemp(I): ArrayTemp(I) = ArrayTemp(j): ArrayTemp(j) = Temp
I = I + 1: j = j - 1
End If
Wend
End If
If (lngMin < j) Then Call QuickSortZV(SortArray, ArrayTemp, lngColumn, lngMin, j, Compare)
If (I < lngMax) Then Call QuickSortZV(SortArray, ArrayTemp, lngColumn, I, lngMax, Compare)
End Sub
Private Sub S_SortH_test()
Dim a, I, j
a = S_SortH(Sheet1.[O4:AH8].Value, -1, False)
End Sub
Function S_SortH(ByVal SortArray, Optional Rows = 0, Optional sortDescending As Boolean)
On Error GoTo E
Dim data, a(), B(), x(), w(), ww(), iw&, iww&, K&, Min&, C&, R&, I&, L&, u&, z()
Dim lb%, ub&, lb2%, ub2&, Compare As VbCompareMethod
Dim lv%, lrow&, row&, V, lines&, fline&, nb&
Dim t1$, t2$, t3$, t4$, it As Boolean
data = SortArray
GoSub I
QuickSortZH data, a, lrow, , , Compare
If u > L Then
fline = lb2: lines = ub2: row = Rows(L + 1): GoSub L
If iw > 0 Then
For lv = L + 1 To u
lrow = Rows(lv):
If lv < u Then
row = Rows(lv + 1)
End If
If iw > 0 Then
ww = w: iw = 0: Erase w
For iww = 1 To UBound(ww, 2)
I = ww(1, iww)
fline = 1
lines = ww(2, iww)
B = ww(3, iww)
Compare = ww(4, iww)
QuickSortZH data, B, lrow, , , Compare
GoSub L
Next
End If
Next
End If
End If
GoSub z
Exit Function
L:
K = 0
For C = fline To lines
If I > 0 Then
nb = C + I - 1
a(nb) = B(C)
Else
nb = C
End If
If lv < u Then
t1 = data(lrow, a(nb))
If K > 0 Then
If t2 <> t1 Then
If K > 1 And it Then
GoSub w
End If
GoTo l2
Else
If Not it Then
t3 = data(row, a(nb))
If t4 <> t3 Then
it = True
End If
End If
End If
Else
l2: K = 0: Min = nb: t4 = data(row, a(nb)): it = False
End If
K = K + 1: GoSub fw
t2 = t1
End If
Next
If K > 1 And it Then
GoSub w
End If
Return
fw:
ReDim Preserve x(1 To K)
x(K) = a(nb)
If Compare = 0 Then
V = data(row, a(nb))
If Not IsNumeric(V) And Not IsDate(V) And V <> vbNullString Then
Compare = 1
End If
End If
Return
w:
iw = iw + 1
ReDim Preserve w(1 To 4, 1 To iw)
w(1, iw) = Min
w(2, iw) = K
w(3, iw) = x
w(4, iw) = Compare: Compare = 0
Return
I:
lb = LBound(data)
ub = UBound(data)
lb2 = LBound(data, 2)
ub2 = UBound(data, 2)
If IsNumeric(Rows) Then
If Rows < lb Then
ReDim z(lb To ub)
For lrow = lb To ub
z(lrow) = lrow
Next
Rows = z
L = lb
u = ub
lrow = Rows(L)
ElseIf Rows > ub Then
S_SortH = data
Exit Function
Else
lrow = Rows
End If
ElseIf IsArray(Rows) Then
L = LBound(Rows)
u = UBound(Rows)
lrow = Rows(L)
Else
Exit Function
End If
ReDim a(lb2 To ub2)
For C = lb2 To ub2
a(C) = C
If Compare = 0 Then
V = data(lrow, C)
If Not IsNumeric(V) And Not IsDate(V) And V <> vbNullString Then
Compare = 1
End If
End If
Next
Return
z:
ReDim z(lb To ub, lb2 To ub2)
If sortDescending Then
For R = lb To ub
For C = lb2 To ub2
z(R, C) = data(R, a(ub - C + 1))
Next
Next
Else
For R = lb To ub
For C = lb2 To ub2
z(R, C) = data(R, a(C))
Next
Next
End If
S_SortH = z
Return
E: S_SortH = data
End Function
Sub QuickSortZH( _
ByVal SortArray As Variant, _
ArrayTemp(), _
Optional lngRow& = -1, _
Optional lngMin& = -1, _
Optional lngMax& = -1, _
Optional Compare As VbCompareMethod = VbCompareMethod.vbBinaryCompare)
On Error Resume Next
Dim I&, j&, varMid, Temp
Dim lngColTemp As Long
If IsEmpty(SortArray) Then Exit Sub
If InStr(TypeName(SortArray), "()") < 1 Then Exit Sub
If lngMin = -1 Then lngMin = LBound(ArrayTemp, 1)
If lngMax = -1 Then lngMax = UBound(ArrayTemp, 1)
If lngMin >= lngMax Then Exit Sub
I = lngMin: j = lngMax
varMid = Empty: varMid = SortArray(lngRow, ArrayTemp((lngMin + lngMax) \ 2))
If IsEmpty(varMid) Then
I = lngMax: j = lngMin
ElseIf IsNull(varMid) Then
I = lngMax: j = lngMin
ElseIf varMid = vbNullString Then
I = lngMax: j = lngMin
ElseIf VarType(varMid) = vbError Then
I = lngMax: j = lngMin
ElseIf VarType(varMid) > 17 Then
I = lngMax: j = lngMin
End If
If Compare = vbBinaryCompare Then
While I <= j
While SortArray(lngRow, ArrayTemp(I)) < varMid And I < lngMax: I = I + 1: Wend
While varMid < SortArray(lngRow, ArrayTemp(j)) And j > lngMin: j = j - 1: Wend
If I <= j Then
Swap1: Temp = ArrayTemp(I): ArrayTemp(I) = ArrayTemp(j): ArrayTemp(j) = Temp
I = I + 1: j = j - 1
End If
Wend
Else
While I <= j
While (StrComp(SortArray(lngRow, ArrayTemp(I)), varMid, 1) = -1 Or (SortArray(lngRow, ArrayTemp(I)) > varMid) And StrComp(SortArray(lngRow, ArrayTemp(I)), varMid, 1) = 0) And I < lngMax: I = I + 1: Wend
While (StrComp(varMid, SortArray(lngRow, ArrayTemp(j)), 1) = -1 Or (varMid > SortArray(lngRow, ArrayTemp(j))) And StrComp(varMid, SortArray(lngRow, ArrayTemp(j)), 1) = 0) And j > lngMin: j = j - 1: Wend
If I <= j Then
Swap2: Temp = ArrayTemp(I): ArrayTemp(I) = ArrayTemp(j): ArrayTemp(j) = Temp
I = I + 1: j = j - 1
End If
Wend
End If
If (lngMin < j) Then Call QuickSortZH(SortArray, ArrayTemp, lngRow, lngMin, j, Compare)
If (I < lngMax) Then Call QuickSortZH(SortArray, ArrayTemp, lngRow, I, lngMax, Compare)
End Sub