Jump to content

Recommended Posts

Posted

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?

Posted

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

Posted

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 here
RegExp tutorial: enough to get started
PCRE 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)

Posted

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

Posted (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 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 here
RegExp tutorial: enough to get started
PCRE 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)

Posted

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

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

Posted (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 by MilesAhead
Posted

Try this.

#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
Posted

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.

Posted (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. :)

Dim $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 by MilesAhead

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...