pixelsearch Posted July 1, 2022 Share Posted July 1, 2022 Hi everybody Here is a function named _ArraySortEx() The major difference with _ArraySort is the possibility to sort naturally, which means ("1", "2", "10") and not ("1", "10", "2). Also, the sort involves the RtlMoveMemory function. As a pic is better than a thousand words... As you can see, I tried to stick to _ArraySort parameters, except for the 6th parameter (and its 6th eventual return error code). Imho the function could be used as a complement to _Arraysort, when a natural sort is needed. I tested it quickly. If you guys find something incorrect in the function, please report here, thanks ! expandcollapse popup#include <Array.au3> Opt( "MustDeclareVars", 1) ;~ Local $aArray[12] = _ ;~ ["wav6", "wav3", "wav11", "wav9", "wav0", "wav8", _ ;~ "wav1", "wav7", "wav10", "wav2", "wav4", "wav5"] ;~ Local $aArray[12] = _ ;~ [6, -3, 11, -9, 0, -8, _ ;~ 1, -7, 10, -2, 4, -5] Local $aArray[12][2] = _ [["wav6", 6], ["wav3", -3], ["wav11", 11], ["wav9", -9], ["wav0", 0], ["wav8", -8], _ ["wav1", 1], ["wav7", -7], ["wav10", 10], ["wav2", -2], ["wav4", 4], ["wav5", -5]] _ArraySortEx($aArray) ; last param default = 2 (natural sort) ;~ _ArraySortEx($aArray, Default, Default, Default, Default, 2) ; 0 = string sort, 1 = numeric sort, 2 = natural sort ;~ _ArraySortEx($aArray, Default, Default, Default, 1, 1) ; sort on col 1 (2D only), numeric sort ;~ _ArraySortEx($aArray, 1) ; descending ;~ _ArraySortEx($aArray, Default, 1) ; start at element 1 ;~ _ArraySortEx($aArray, Default, Default, 10) ; end at element 10 ;~ _ArraySortEx($aArray, Default, 1, 10) ; start at element 1, end at element 10 If @error Then Exit Msgbox(0, "_ArraySortEx", "error = " & @error) _ArrayDisplay($aArray) ;============================== Func _ArraySortEx(ByRef $aArray, $iDescending = 0, $iStart = 0, $iEnd = 0, $iSubItem = 0, $iType = 2) If $iDescending = Default Then $iDescending = 0 If $iStart = Default Then $iStart = 0 If $iEnd = Default Then $iEnd = 0 If $iSubItem = Default Then $iSubItem = 0 If $iType = Default Then $iType = 2 ; 0 = string sort, 1 = numeric sort, 2 = natural sort If Not IsArray($aArray) Then Return SetError(1, 0, 0) Local $iDims = UBound($aArray, $UBOUND_DIMENSIONS) If $iDims < 1 Or $iDims > 2 Then Return SetError(4, 0, 0) Local $iRows = UBound($aArray, $UBOUND_ROWS) If $iRows = 0 Then Return SetError(5, 0, 0) Local $iCols = UBound($aArray, $UBOUND_COLUMNS) ; always 0 for 1D array If $iDims = 2 And $iSubItem > $iCols - 1 Then Return SetError(3, 0, 0) If $iType < 0 Or $iType > 2 Then Return SetError(6, 0, 0) ; Bounds checking If $iStart < 0 Then $iStart = 0 If $iEnd <= 0 Or $iEnd > $iRows - 1 Then $iEnd = $iRows - 1 If $iStart > $iEnd Then Return SetError(2, 0, 0) Local $tIndex = DllStructCreate("uint[" & ($iEnd - $iStart + 1) & "]") Local $pIndex = DllStructGetPtr($tIndex) Local $hDll = DllOpen("kernel32.dll") Local $hDllComp = DllOpen("shlwapi.dll") Local $lo, $hi, $mi, $r, $nVal1, $nVal2 For $i = 1 To $iEnd - $iStart $lo = 0 $hi = $i - 1 If $iDims = 1 Then ; 1D Do $mi = Int(($lo + $hi) / 2) Switch $iType Case 2 ; Natural Sort $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', String($aArray[$i + $iStart]), _ 'wstr', String($aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart]))[0] Case 1 ; Numeric Sort $nVal1 = Number($aArray[$i + $iStart]) $nVal2 = Number($aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart]) $r = $nVal1 < $nVal2 ? -1 : $nVal1 > $nVal2 ? 1 : 0 Case Else ; 0 = String Sort $r = StringCompare($aArray[$i + $iStart], $aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart]) EndSwitch Switch $r Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi Else ; 2D Do $mi = Int(($lo + $hi) / 2) Switch $iType Case 2 ; Natural Sort $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', String($aArray[$i + $iStart][$iSubItem]), _ 'wstr', String($aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart][$iSubItem]))[0] Case 1 ; Numeric Sort $nVal1 = Number($aArray[$i + $iStart][$iSubItem]) $nVal2 = Number($aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart][$iSubItem]) $r = $nVal1 < $nVal2 ? -1 : $nVal1 > $nVal2 ? 1 : 0 Case Else ; 0 = String Sort $r = StringCompare($aArray[$i + $iStart][$iSubItem], _ $aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iStart][$iSubItem]) EndSwitch Switch $r Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi EndIf DllCall($hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ($mi + 1) * 4, _ "struct*", $pIndex + $mi * 4, "ulong_ptr", ($i - $mi) * 4) DllStructSetData($tIndex, 1, $i, $mi + 1 + ($lo = $mi + 1)) Next Local $aBackup = $aArray If $iDims = 1 Then ; 1D If Not $iDescending Then For $i = 0 To $iEnd - $iStart $aArray[$i + $iStart] = $aBackup[DllStructGetData($tIndex, 1, $i + 1) + $iStart] Next Else ; descending For $i = 0 To $iEnd - $iStart $aArray[$iEnd - $i] = $aBackup[DllStructGetData($tIndex, 1, $i + 1) + $iStart] Next EndIf Else ; 2D Local $iIndex If Not $iDescending Then For $i = 0 To $iEnd - $iStart $iIndex = DllStructGetData($tIndex, 1, $i + 1) + $iStart For $j = 0 To $iCols - 1 $aArray[$i + $iStart][$j] = $aBackup[$iIndex][$j] Next Next Else ; descending For $i = 0 To $iEnd - $iStart $iIndex = DllStructGetData($tIndex, 1, $i + 1) + $iStart For $j = 0 To $iCols - 1 $aArray[$iEnd - $i][$j] = $aBackup[$iIndex][$j] Next Next EndIf EndIf $tIndex = 0 DllClose($hDll) DllClose($hDllComp) Return 1 EndFunc ;==>_ArraySortEx Musashi and Mateocedillo 2 Link to comment Share on other sites More sharing options...
Musashi Posted July 1, 2022 Share Posted July 1, 2022 2 hours ago, pixelsearch said: I tested it quickly. If you guys find something incorrect in the function, please report here, thanks ! I performed some tests as well and everything seems to be working . One, probably silly note (was a long day at the office and I'm fairly done) : The numerical sorting of an array where all elements do not start with digits does not make much sense, right ? In such a case the natural sorting is appropriate. pixelsearch 1 "In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move." Link to comment Share on other sites More sharing options...
pixelsearch Posted July 1, 2022 Author Share Posted July 1, 2022 (edited) Hi Musashi Thanks for your tests, much appreciated On 7/1/2022 at 8:14 PM, Musashi said: The numerical sorting of an array where all elements do not start with digits does not make much sense, right ? In such a case the natural sorting is appropriate. I agree. That's why all possibilities are found in the function (string sort, numeric sort, natural sort) though the function _ArraySortEx should be used mainly for Natural Sort (which doesn't exist in _ArraySort), i.e. "wav1" => "wav2" => "wav10" after the sort is done. When it comes to String Sort ("wav1" => "wav10" => "wav2") or Numeric Sort, then _ArraySort seems faster. If speed is the most concern (because of very big arrays) then the C++ code & external dll will sort 10 times faster, as shown in this post. Edited July 3, 2022 by pixelsearch _ArraySortEx should be used mainly for Natural sort Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now