Sign in to follow this  
Followers 0
dost0011

Bug or Feature: _Arraysort()

11 posts in this topic

Hi,

I took a really long time to find out, that _Arraysort() is doing something I really don't understand.

I created a string: Filename & "Separation" & Size & "Separation" & DateoftheFile

and wrote this string to an array.

Ok, then I startet to sort the array and I couldn't believe it - the result is not depending from the Filename but from the DateoftheFile !!!

Here is a very short example to show the problem:

The first part is ok - and the second part is changing the order?!? ;)

#include <array.au3>

DIM $array[2]

$array[0] = "A" & chr(2); & "2"
$array[1] = "A1" & chr(2); & "2"
_ArraySort($array, 0, 0, 2)
MsgBox(0,"1",$array[0])
MsgBox(0,"2",$array[1])

;-------------------------
$array[0] = "A" & chr(2) & "2"
$array[1] = "A1" & chr(2) & "2"
_ArraySort($array, 0, 0, 2)

MsgBox(0,"1",$array[0])
MsgBox(0,"2",$array[1])

I tried the same with the faster ArrayIntroSort_1D - but it's the same.

How can I sort the Arrays without the "Feature" that Number at the last is turning my result?

Many thanks!

Share this post


Link to post
Share on other sites



Yuck. That looks broke to me. I started to blame that on the non-printable delimiter (Chr(2) = [sTX]) but even with something like "xx" for a delimiter, the sort fails the exact same way:

#include <array.au3>

Dim $array[10]

For $n = 0 To 9
    If Mod($n, 2) Then
        ; Odd, add $n
        $array[$n] = "A" & $n & "xx" & "2"
    Else
        ; Even no $n
        $array[$n] = "A" & "xx" & "2"
    EndIf
Next
_ArrayDisplay($array, "BEFORE")
_ArraySort($array, 0, 0, 2)
_ArrayDisplay($array, "AFTER")

Regardless of which way the compare wants to treat them, the strings "Axx2" should have been grouped together at the top or bottom of the array after sorting.

;)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

Regardless of which way the compare wants to treat them, the strings "Axx2" should have been grouped together at the top or bottom of the array after sorting.

;)

What about this version? :evil:

#include <array.au3>

Dim $array[10]

For $n = 0 To 9
    If Mod($n, 2) Then
        ; Odd, add $n
        $array[$n] = "A" & $n & "xx" & "2"
    Else
        ; Even no $n
        $array[$n] = "A" & "xx" & "2"
    EndIf
Next
_ArrayDisplay($array, "BEFORE")
$x=_ArraySort($array)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $x = ' & $x & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
_ArrayDisplay($array, "AFTER")

Visit the SciTE4AutoIt3 Download page for the latest versions        Beta files                                                          Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Its StringCompare that looks not being consequent here.

Dim $array[2]

$array[0] = "A" & Chr(2); & "2"
$array[1] = "A1" & Chr(2); & "2"
ConsoleWrite(StringCompare($array[0], $array[1]) & @CRLF)
;-------------------------
$array[0] = "A" & Chr(2) & "2"
$array[1] = "A1" & Chr(2) & "2"
ConsoleWrite(StringCompare($array[0], $array[1]) & @CRLF)

Result:

-1
1
Edited by Jos

Visit the SciTE4AutoIt3 Download page for the latest versions        Beta files                                                          Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

<stupidity deleted>

;)

Edit: NVM, I don't believe I missed that parameter. Well, yes I do... :evil:

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

See the demo in my earlier post where several "Axx2" strings wind up sprinkled through the array instead of all at the top or all at the bottom together.

;)

Did you see my answer to that one? I think you made an error on the _ArraySort() statement. :evil:

Visit the SciTE4AutoIt3 Download page for the latest versions        Beta files                                                          Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Did you see my answer to that one? I think you made an error on the _ArraySort() statement. :evil:

<hang head>

<shuffle feet style='sheepishly'>

Yeah...

</shuffle>

</hang>

Still looks like the non-printing characters still throw it off:

[0] = A1[STX]2
[1] = A[STX]2
[2] = A[STX]2
[3] = A[STX]2
[4] = A[STX]2
[5] = A[STX]2
[6] = A3[STX]2
[7] = A5[STX]2
[8] = A7[STX]2
[9] = A9[STX]2

But this is right if it treats non-printing characters as numeric strings i.e. String(ASC(Chr(2))), because that makes the result:

[0] = A122
[1] = A22
[2] = A22
[3] = A22
[4] = A22
[5] = A22
[6] = A322
[7] = A522
[8] = A722
[9] = A922

;)

Edit: That doesn't work either because with Chr(5) = [ENQ] it sorts exactly the same:

[0] = A1[ENQ]2
[1] = A[ENQ]2
[2] = A[ENQ]2
[3] = A[ENQ]2
[4] = A[ENQ]2
[5] = A[ENQ]2
[6] = A3[ENQ]2
[7] = A5[ENQ]2
[8] = A7[ENQ]2
[9] = A9[ENQ]2

An actual "5" sorts as expected:

[0] = A152
[1] = A352
[2] = A52
[3] = A52
[4] = A52
[5] = A52
[6] = A52
[7] = A552
[8] = A752
[9] = A952

:evil:

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

It looks like these characters are ignored. I haven't looked inside the source code yet but this seems to work:

Dim $array[2]
$array[0] = "A" & Chr(2); & "2"
$array[1] = "A1" & Chr(2); & "2"
ConsoleWrite(StringCompare($array[0], $array[1], 1) & @CRLF)
;-------------------------
$array[0] = "A" & Chr(2) & "2"
$array[1] = "A1" & Chr(2) & "2"
ConsoleWrite(StringCompare($array[0], $array[1], 1) & @CRLF)
Edited by Jos

Visit the SciTE4AutoIt3 Download page for the latest versions        Beta files                                                          Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

It looks like these characters are ignored. I haven't looked inside the source code yet but this seems to work:

Dim $array[2]
$array[0] = "A" & Chr(2); & "2"
$array[1] = "A1" & Chr(2); & "2"
ConsoleWrite(StringCompare($array[0], $array[1], 1) & @CRLF)
;-------------------------
$array[0] = "A" & Chr(2) & "2"
$array[1] = "A1" & Chr(2) & "2"
ConsoleWrite(StringCompare($array[0], $array[1], 1) & @CRLF)

This is interesting.

I think default StringCompare (casesense param = 0) uses CompareStringW function to do the job. Seems like with LOCALE_SYSTEM_DEFAULT (0x400) passed as 'Locale' parameter and NORM_IGNORECASE (1) as 'CmpFlags' parameter. This doesn't follow the description in the help file btw. Help file says user's locale.

With other two flags seems like custom written functions are used.

Anyway, it's not about ignoring characters. Nothing is ignored.


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Hi guys,

I couldn't follow you at all.

Could you please explain what I can do to solve my problem?

Is it a bug or not?

Many thanks.

Share this post


Link to post
Share on other sites

Hi guys,

I couldn't follow you at all.

Could you please explain what I can do to solve my problem?

Is it a bug or not?

Many thanks.

;<- !Here!:

;#include <array.au3>

DIM $array[2]

$array[0] = "A" & chr(2); & "2"
$array[1] = "A1" & chr(2); & "2"
_ArraySort($array, 0, 0, 2)
MsgBox(0,"1",$array[0])
MsgBox(0,"2",$array[1])

;-------------------------
$array[0] = "A" & chr(2) & "2"
$array[1] = "A1" & chr(2) & "2"
_ArraySort($array, 0, 0, 2)

MsgBox(0,"1",$array[0])
MsgBox(0,"2",$array[1])


; #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, Jos van der Zande - changed logic to correctly Sort arrays with mixed Values and Strings, Ultima - major optimization, code cleanup, removed $i_Dim parameter
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _ArraySort(ByRef $avArray, $iDescending = 0, $iStart = 0, $iEnd = 0, $iSubItem = 0)
    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)
            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)
        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.......:
; Remarks .......: For Internal Use Only
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func __ArrayQuickSort1D(ByRef $avArray, ByRef $iStart, ByRef $iEnd)
    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 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], 2) >= 0) Then ExitLoop ;<- !Here!
                    $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 $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)
    __ArrayQuickSort1D($avArray, $L, $iEnd)
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.......:
; Remarks .......: For Internal Use Only
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func __ArrayQuickSort2D(ByRef $avArray, ByRef $iStep, ByRef $iStart, ByRef $iEnd, ByRef $iSubItem, ByRef $iSubMax)
    If $iEnd <= $iStart Then Return

    ; QuickSort
    Local $vTmp, $L = $iStart, $R = $iEnd, $vPivot = $avArray[Int(($iStart + $iEnd) / 2)][$iSubItem], $fNum = IsNumber($vPivot)
    Do
        If $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)
    __ArrayQuickSort2D($avArray, $iStep, $L, $iEnd, $iSubItem, $iSubMax)
EndFunc   ;==>__ArrayQuickSort2D

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

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

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
Sign in to follow this  
Followers 0