tsolrm Posted March 9, 2012 Posted March 9, 2012 Hi guys, i need some help please I've got a list (about 100 entries) test,1,user,6,2,1570 test2,1,user,5,4,1535 test3,1,user,4,5,1510 test4,1,user,2,0,1530 test5,1,user,0,2,1480 test6,1,user,0,0,1500 That has to be arranged into descending order using the last 4 digit number like this test,1,user,6,2,1570 test2,1,user,5,4,1535 test4,1,user,2,0,1530 test3,1,user,4,5,1510 test6,1,user,0,0,1500 Whats the quickest way to do this?
kylomas Posted March 9, 2012 Posted March 9, 2012 tsolrm, Move the string that you want to sort on to the front of the entry, load the entries to an array, _arraysort, write entries back to whatever moving the string back to the end. kylomas Forum Rules Procedure for posting code "I like pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals." - Sir Winston Churchill
jchd Posted March 9, 2012 Posted March 9, 2012 Ahem, _ArraySort has a parameter to specify which column of a 2D array you want to sort on. This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)
kylomas Posted March 9, 2012 Posted March 9, 2012 @jchd, Even better, thank you ! kylomas Forum Rules Procedure for posting code "I like pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals." - Sir Winston Churchill
tsolrm Posted March 9, 2012 Author Posted March 9, 2012 But this wouldn't be a 2D array.. If i create a separate array with the numbers and sort them using _arraysort then how do i match the rest of the data to the sorted items
jchd Posted March 9, 2012 Posted March 9, 2012 (edited) Place them in one column of a 2D array and place line (or whatever) index in the other column. If the thing is not too fat, just put the whole string in the other column! Edited March 9, 2012 by jchd This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)
tsolrm Posted March 9, 2012 Author Posted March 9, 2012 i'm sorry but i don't get what you mean by this
kylomas Posted March 9, 2012 Posted March 9, 2012 tsolrm, Something like this will work (needs cleaning up). I changed the input string to be delimited by a "|" character. ; ; ; #include <array.au3> $str = "test,1,user,6,2,1570 | test2,1,user,5,4,1535 | test3,1,user,4,5,1510 | test4,1,user,2,0,1530 | test5,1,user,0,2,1480 | test6,1,user,0,0,1500" Local $a10[7][7] $a20 = StringSplit($str,"|") For $i = 0 To $a20[0] $a30 = StringSplit($a20[$i],',') For $j = 0 To $a30[0] $a10[$i][$j] = $a30[$j] Next Next _arraydisplay($a10) _arraysort($a10,0,0,0,6) _arraydisplay($a10) kylomas tsolrm 1 Forum Rules Procedure for posting code "I like pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals." - Sir Winston Churchill
MilesAhead Posted March 9, 2012 Posted March 9, 2012 (edited) I'm surprised someone hasn't modified the array qsort to pass in a comparison function. Something like Func MyStringCompare($left, $right) Return StringCompare(StringRight($left,4),StringRight($right,4)) EndFunc If the _ArraySort() authors don't mind code lifting it should be pretty easy to just pass in a custom compare. Edited March 9, 2012 by MilesAhead My Freeware Page
UEZ Posted March 9, 2012 Posted March 9, 2012 Have a look here: Might be useful, too. Br, UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Malkey Posted March 9, 2012 Posted March 9, 2012 Try this. expandcollapse popup#include <Array.au3> ; Modified from http://www.autoitscript.com/forum/index.php?showtopic=108860&view=findpost&p=766431 Local $aArray[6] $aArray[0] = "test,1,user,6,2,1570" $aArray[1] = "test2,1,user,5,4,1535" $aArray[2] = "test3,1,user,4,5,1510" $aArray[3] = "test4,1,user,2,0,1530" $aArray[4] = "test5,1,user,0,2,1480" $aArray[5] = "test6,1,user,0,0,1500" _ArraySortCust($aArray, "(?m)(?:.+)(d{4})$") _ArrayDisplay($aArray) ; Description - Sorts a 1D array on the match returned from the RE pattern applied to each element of the array. Func _ArraySortCust(ByRef $aArr, $sREPattern) Local $iFlag = 1, $sTemp, $iPrev, $iThis While $iFlag = 1 $iFlag = 0 For $i = 1 To UBound($aArr) - 1 $iPrev = Number(StringRegExpReplace($aArr[$i - 1], $sREPattern, "1")) $iThis = Number(StringRegExpReplace($aArr[$i], $sREPattern, "1")) ; ==== 1st sort ======== ;ConsoleWrite($iPrev & " " & $iThis & @CRLF) ; Sort highest number to lowest number order. If $iPrev < $iThis Then $iFlag = 1 ; Cause While loop to loop one more time. $sTemp = $aArr[$i - 1] ; Swap routine $aArr[$i - 1] = $aArr[$i] $aArr[$i] = $sTemp EndIf ; ======2nd sort ======== ;ConsoleWrite(StringRegExpReplace($aArr[$i-1], $sREPattern, "1") & " " & StringRegExpReplace($aArr[$i], $sREPattern, "1") & @CRLF) ; If numbers are equal then sort on what follows the numbers A to Z order. If ($iPrev = $iThis) And (StringRegExpReplace($aArr[$i - 1], $sREPattern, "1") > StringRegExpReplace($aArr[$i], $sREPattern, "1")) Then $iFlag = 1 $sTemp = $aArr[$i - 1] ; Swap routine $aArr[$i - 1] = $aArr[$i] $aArr[$i] = $sTemp EndIf Next ;ConsoleWrite("$iFlag = " & $iFlag & @CRLF & @CRLF) WEnd EndFunc ;==>_ArraySortCust
MilesAhead Posted March 9, 2012 Posted March 9, 2012 In c based languages usually QSort has a comparison function passed in through a pointer. To make it general purpose I was thinking something like Call() might do the trick. The stipulation would be the same as in C/C++ or StringCompare return values. Header something like Func _ArraySortCustom(ByRef $avArray,$compare_func) ; usual qsort partitioning code ;instead of hard wiring StringCompare use If Call($compare_func,$left,$right) < 0 then ; blah blah Then it would be general purpose, strings, numbers, zip codes, whatever. Just write the $compare_func. My Freeware Page
MilesAhead Posted March 12, 2012 Posted March 12, 2012 (edited) Maybe someone can test to see if I got it right. I just used StringCompare to see if the stuff passed through ok. But this mod should allow a user defined compare function to be applied without breaking normal usage. The compare function should take 2 params and return the same as StringCompare(). Note I just pasted in the used functions from Array.au3 so I wouldn't have to include the file in the test case. Edit: another possible optimization: when using iCompare, if the array is to be sorted in decending order, multiply the iCompare result by -1 to sort on the fly rather than calling _ArrayReverse() at the end. Edit2: I see the authors used the multiply by -1 technique when sorting 2D arrays. I suppose they figured in most cases the 1D array reverse would be nearly as fast. In any case many objects with a sort method just instruct the user to provide a comparison function that returns a reverse compare if they want a reverse sort. Get rid of the Descending param altogether. But the point here is to modify without breaking existing code. Edit3: During search I noticed someone posted a thread _ArraySortMod() in 2007 wanting to have a comparison function as a param invoked using Call().. Guess I won't hold my breath. expandcollapse popupDim $testArray[8] = ["crap", "sand", "garbage", "dirt", "filth", "dust", "lint", "hair"] _ArraySort($testArray, 0, 0, 0, 0, "CustomCompare") If @error Then MsgBox(0x1010,"Error", "Some Error!") Exit EndIf For $x = 0 To UBound($testArray) - 1 MsgBox(0x1040,"Test", $testArray[$x]) Next Func CustomCompare($left, $right) Return StringCompare($left, $right) EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: _ArraySort ; Description ...: Sort a 1D or 2D array on a specific index using the quicksort/insertionsort algorithms. ; Syntax.........: _ArraySort(ByRef $avArray[, $iDescending = 0[, $iStart = 0[, $iEnd = 0[, $iSubItem = 0]]]]) ; Parameters ....: $avArray - Array to sort ; $iDescending - [optional] If set to 1, sort descendingly ; $iStart - [optional] Index of array to start sorting at ; $iEnd - [optional] Index of array to stop sorting at ; $iSubItem - [optional] Sub-index to sort on in 2D arrays ; Return values .: Success - 1 ; Failure - 0, sets @error: ; |1 - $avArray is not an array ; |2 - $iStart is greater than $iEnd ; |3 - $iSubItem is greater than subitem count ; |4 - $avArray has too many dimensions ; Author ........: Jos van der Zande <jdeb at="" autoitscript="" dot="" com=""> ; Modified.......: LazyCoder - added $iSubItem option, Tylo - implemented stable QuickSort algo, ; Modified.......: Jos van der Zande - changed logic to correctly Sort arrays with mixed Values and Strings, ; Modified.......: Ultima - major optimization, code cleanup, removed $i_Dim parameter ; Modified.......: MilesAhead - added user defined $iCompare for generalized qsort() ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: Yes ; =============================================================================================================================== Func _ArraySort(ByRef $avArray, $iDescending = 0, $iStart = 0, $iEnd = 0, $iSubItem = 0, $iCompare = "") If Not IsArray($avArray) Then Return SetError(1, 0, 0) Local $iUBound = UBound($avArray) - 1 ; Bounds checking If $iEnd < 1 Or $iEnd > $iUBound Then $iEnd = $iUBound If $iStart < 0 Then $iStart = 0 If $iStart > $iEnd Then Return SetError(2, 0, 0) ; Sort Switch UBound($avArray, 0) Case 1 __ArrayQuickSort1D($avArray, $iStart, $iEnd, $iCompare) If $iDescending Then _ArrayReverse($avArray, $iStart, $iEnd) Case 2 Local $iSubMax = UBound($avArray, 2) - 1 If $iSubItem > $iSubMax Then Return SetError(3, 0, 0) If $iDescending Then $iDescending = -1 Else $iDescending = 1 EndIf __ArrayQuickSort2D($avArray, $iDescending, $iStart, $iEnd, $iSubItem, $iSubMax, $iCompare) Case Else Return SetError(4, 0, 0) EndSwitch Return 1 EndFunc ;==>_ArraySort ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: __ArrayQuickSort1D ; Description ...: Helper function for sorting 1D arrays ; Syntax.........: __ArrayQuickSort1D(ByRef $avArray, ByRef $iStart, ByRef $iEnd) ; Parameters ....: $avArray - Array to sort ; $iStart - Index of array to start sorting at ; $iEnd - Index of array to stop sorting at ; Return values .: None ; Author ........: Jos van der Zande, LazyCoder, Tylo, Ultima ; Modified.......: MilesAhead - added user defined $iCompare for generalized qsort() ; Remarks .......: For Internal Use Only ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func __ArrayQuickSort1D(ByRef $avArray, ByRef $iStart, ByRef $iEnd, $iCompare = "") If $iEnd <= $iStart Then Return Local $vTmp ; InsertionSort (faster for smaller segments) If ($iEnd - $iStart) < 15 Then Local $vCur For $i = $iStart + 1 To $iEnd $vTmp = $avArray[$i] If $iCompare Then For $j = $i - 1 To $iStart Step -1 If (Call($iCompare,$vTmp, $avArray[$j]) >= 0) Then ExitLoop $avArray[$j + 1] = $avArray[$j] Next ElseIf IsNumber($vTmp) Then For $j = $i - 1 To $iStart Step -1 $vCur = $avArray[$j] ; If $vTmp >= $vCur Then ExitLoop If ($vTmp >= $vCur And IsNumber($vCur)) Or (Not IsNumber($vCur) And StringCompare($vTmp, $vCur) >= 0) Then ExitLoop $avArray[$j + 1] = $vCur Next Else For $j = $i - 1 To $iStart Step -1 If (StringCompare($vTmp, $avArray[$j]) >= 0) Then ExitLoop $avArray[$j + 1] = $avArray[$j] Next EndIf $avArray[$j + 1] = $vTmp Next Return EndIf ; QuickSort Local $L = $iStart, $R = $iEnd, $vPivot = $avArray[Int(($iStart + $iEnd) / 2)], $fNum = IsNumber($vPivot) Do If $iCompare Then While (Call($iCompare,$avArray[$L], $vPivot) < 0) $L += 1 WEnd ; While $avArray[$R] > $vPivot While (Call($iCompare,$avArray[$R], $vPivot) > 0) $R -= 1 WEnd ElseIf $fNum Then ; While $avArray[$L] < $vPivot While ($avArray[$L] < $vPivot And IsNumber($avArray[$L])) Or (Not IsNumber($avArray[$L]) And StringCompare($avArray[$L], $vPivot) < 0) $L += 1 WEnd ; While $avArray[$R] > $vPivot While ($avArray[$R] > $vPivot And IsNumber($avArray[$R])) Or (Not IsNumber($avArray[$R]) And StringCompare($avArray[$R], $vPivot) > 0) $R -= 1 WEnd Else While (StringCompare($avArray[$L], $vPivot) < 0) $L += 1 WEnd While (StringCompare($avArray[$R], $vPivot) > 0) $R -= 1 WEnd EndIf ; Swap If $L <= $R Then $vTmp = $avArray[$L] $avArray[$L] = $avArray[$R] $avArray[$R] = $vTmp $L += 1 $R -= 1 EndIf Until $L > $R __ArrayQuickSort1D($avArray, $iStart, $R, $iCompare) __ArrayQuickSort1D($avArray, $L, $iEnd, $iCompare) EndFunc ;==>__ArrayQuickSort1D ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: __ArrayQuickSort2D ; Description ...: Helper function for sorting 2D arrays ; Syntax.........: __ArrayQuickSort2D(ByRef $avArray, ByRef $iStep, ByRef $iStart, ByRef $iEnd, ByRef $iSubItem, ByRef $iSubMax) ; Parameters ....: $avArray - Array to sort ; $iStep - Step size (should be 1 to sort ascending, -1 to sort descending!) ; $iStart - Index of array to start sorting at ; $iEnd - Index of array to stop sorting at ; $iSubItem - Sub-index to sort on in 2D arrays ; $iSubMax - Maximum sub-index that array has ; Return values .: None ; Author ........: Jos van der Zande, LazyCoder, Tylo, Ultima ; Modified.......: MilesAhead - added user defined $iCompare for generalized qsort() ; Remarks .......: For Internal Use Only ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func __ArrayQuickSort2D(ByRef $avArray, ByRef $iStep, ByRef $iStart, ByRef $iEnd, ByRef $iSubItem, ByRef $iSubMax, $iCompare = "") If $iEnd <= $iStart Then Return ; QuickSort Local $vTmp, $L = $iStart, $R = $iEnd, $vPivot = $avArray[Int(($iStart + $iEnd) / 2)][$iSubItem], $fNum = IsNumber($vPivot) Do If $iCompare Then While (Call($iCompare,$avArray[$L][$iSubItem], $vPivot) < 0) $L += 1 WEnd While (Call($iCompare,$avArray[$R][$iSubItem], $vPivot) > 0) $R -= 1 WEnd ElseIf $fNum Then ; While $avArray[$L][$iSubItem] < $vPivot While ($iStep * ($avArray[$L][$iSubItem] - $vPivot) < 0 And IsNumber($avArray[$L][$iSubItem])) Or (Not IsNumber($avArray[$L][$iSubItem]) And $iStep * StringCompare($avArray[$L][$iSubItem], $vPivot) < 0) $L += 1 WEnd ; While $avArray[$R][$iSubItem] > $vPivot While ($iStep * ($avArray[$R][$iSubItem] - $vPivot) > 0 And IsNumber($avArray[$R][$iSubItem])) Or (Not IsNumber($avArray[$R][$iSubItem]) And $iStep * StringCompare($avArray[$R][$iSubItem], $vPivot) > 0) $R -= 1 WEnd Else While ($iStep * StringCompare($avArray[$L][$iSubItem], $vPivot) < 0) $L += 1 WEnd While ($iStep * StringCompare($avArray[$R][$iSubItem], $vPivot) > 0) $R -= 1 WEnd EndIf ; Swap If $L <= $R Then For $i = 0 To $iSubMax $vTmp = $avArray[$L][$i] $avArray[$L][$i] = $avArray[$R][$i] $avArray[$R][$i] = $vTmp Next $L += 1 $R -= 1 EndIf Until $L > $R __ArrayQuickSort2D($avArray, $iStep, $iStart, $R, $iSubItem, $iSubMax, $iCompare) __ArrayQuickSort2D($avArray, $iStep, $L, $iEnd, $iSubItem, $iSubMax, $iCompare) EndFunc ;==>__ArrayQuickSort2D ; #FUNCTION# ==================================================================================================================== ; Name...........: _ArraySwap ; Description ...: Swaps two items. ; Syntax.........: _ArraySwap(ByRef $vItem1, ByRef $vItem2) ; Parameters ....: $vItem1 - First item to swap ; $vItem2 - Second item to swap ; Return values .: None. ; Author ........: David Nuttall <danuttall at="" rocketmail="" dot="" com=""> ; Modified.......: Ultima - minor optimization ; Remarks .......: This function swaps the two items in place, since they're passed by reference. Regular, non-array variables can also be swapped by this function. ; Related .......: _ArrayReverse ; Link ..........: ; Example .......: Yes ; =============================================================================================================================== Func _ArraySwap(ByRef $vItem1, ByRef $vItem2) Local $vTmp = $vItem1 $vItem1 = $vItem2 $vItem2 = $vTmp EndFunc ;==>_ArraySwap ; #FUNCTION# ==================================================================================================================== ; Name...........: _ArrayReverse ; Description ...: Takes the given array and reverses the order in which the elements appear in the array. ; Syntax.........: _ArrayReverse(ByRef $avArray[, $iStart = 0[, $iEnd = 0]]) ; Parameters ....: $avArray - Array to modify ; $iStart - [optional] Index of array to start modifying at ; $iEnd - [optional] Index of array to stop modifying at ; Return values .: Success - 1 ; Failure - 0, sets @error: ; |1 - $avArray is not an array ; |2 - $iStart is greater than $iEnd ; |3 - $avArray is not a 1 dimensional array ; Author ........: Brian Keene ; Modified.......: Jos van der Zande <jdeb at="" autoitscript="" dot="" com=""> - added $iStart parameter and logic, Tylo - added $iEnd parameter and rewrote it for speed, Ultima - code cleanup, minor optimization ; Remarks .......: ; Related .......: _ArraySwap ; Link ..........: ; Example .......: Yes ; =============================================================================================================================== Func _ArrayReverse(ByRef $avArray, $iStart = 0, $iEnd = 0) If Not IsArray($avArray) Then Return SetError(1, 0, 0) If UBound($avArray, 0) <> 1 Then Return SetError(3, 0, 0) Local $vTmp, $iUBound = UBound($avArray) - 1 ; Bounds checking If $iEnd < 1 Or $iEnd > $iUBound Then $iEnd = $iUBound If $iStart < 0 Then $iStart = 0 If $iStart > $iEnd Then Return SetError(2, 0, 0) ; Reverse For $i = $iStart To Int(($iStart + $iEnd - 1) / 2) $vTmp = $avArray[$i] $avArray[$i] = $avArray[$iEnd] $avArray[$iEnd] = $vTmp $iEnd -= 1 Next Return 1 EndFunc ;==>_ArrayReverse Edited November 19, 2012 by MilesAhead My Freeware Page
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