Jump to content
HHS

ARRAY.AU3 / _ArrayBinarySearch() / Bugfix

Recommended Posts

HHS

Hello,

I have found a "bug" in array.au3 in the function _ArrayBinarySearch().

Summary:

Not possible to get the correct index of an element when use "ß", they found always "ss".

 

Here a little Test-Script:

#include <Array.au3>

Local $Array[6] = ["a_ausser", "a_außer", "b_ausser", "b_außer", "c_ausser", "c_außer"]
_ArraySort($Array, 0, 0)
For $i=0 to UBound($Array)-1
    ConsoleWrite("Index " & $i & ": " & $Array[$i] & @CRLF)
Next

;BinarySearch
ConsoleWrite("BinarySearchIndex: " & _ArrayBinarySearch($Array, "b_außer", 0) & " <-- must be Index 3 - b_außer" & @CRLF)
ConsoleWrite("BinarySearchIndex: " & _ArrayBinarySearch($Array, "b_ausser", 0) & " <-- must be Index 2 - b_ausser" & @CRLF)

Output:

--> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop
Index 0: a_ausser
Index 1: a_außer
Index 2: b_ausser
Index 3: b_außer
Index 4: c_ausser
Index 5: c_außer
BinarySearchIndex: 2 <-- must be Index 3 - b_außer
BinarySearchIndex: 2 <-- must be Index 2 - b_ausser
+>09:35:08 AutoIt3.exe ended.rc:0

Here is the wrong item with Index 2 found, but I search for item 3

 

now HERE my little bugfix in __ArrayBinarySearch():

#include <Array.au3>

Local $Array[6] = ["a_ausser", "a_außer", "b_ausser", "b_außer", "c_ausser", "c_außer"]
_ArraySort($Array, 0, 0)
For $i=0 to UBound($Array)-1
    ConsoleWrite("Index " & $i & ": " & $Array[$i] & @CRLF)
Next

;BinarySearch
ConsoleWrite("BinarySearchIndex: " & __ArrayBinarySearch($Array, "b_außer", 0) & " <-- must be Index 3 - b_außer" & @CRLF)
ConsoleWrite("BinarySearchIndex: " & __ArrayBinarySearch($Array, "b_ausser", 0) & " <-- must be Index 2 - b_ausser" & @CRLF)


; #FUNCTION# ====================================================================================================================
; Author ........: Jos
; Modified.......: Ultima - added $iEnd as parameter, code cleanup; Melba23 - added support for empty & 2D arrays
; ===============================================================================================================================
Func __ArrayBinarySearch(Const ByRef $aArray, $vValue, $iStart = 0, $iEnd = 0, $iColumn = 0)
    If $iStart = Default Then $iStart = 0
    If $iEnd = Default Then $iEnd = 0
    If $iColumn = Default Then $iColumn = 0
    If Not IsArray($aArray) Then Return SetError(1, 0, -1)
    ; Bounds checking
    Local $iDim_1 = UBound($aArray, $UBOUND_ROWS)
    If $iDim_1 = 0 Then Return SetError(6, 0, -1)
    If $iEnd < 1 Or $iEnd > $iDim_1 - 1 Then $iEnd = $iDim_1 - 1
    If $iStart < 0 Then $iStart = 0
    If $iStart > $iEnd Then Return SetError(4, 0, -1)
    Local $iMid = Int(($iEnd + $iStart) / 2)
    Switch UBound($aArray, $UBOUND_DIMENSIONS)
        Case 1
            If $aArray[$iStart] > $vValue Or $aArray[$iEnd] < $vValue Then Return SetError(2, 0, -1)
            ; Search
            While $iStart <= $iMid And Not ($vValue == $Array[$iMid])
                If $vValue < $aArray[$iMid] Then
                    $iEnd = $iMid - 1
                Else
                    $iStart = $iMid + 1
                EndIf
                $iMid = Int(($iEnd + $iStart) / 2)
            WEnd
            If $iStart > $iEnd Then Return SetError(3, 0, -1) ; Entry not found
        Case 2
            Local $iDim_2 = UBound($aArray, $UBOUND_COLUMNS) - 1
            If $iColumn < 0 Or $iColumn > $iDim_2 Then Return SetError(7, 0, -1)
            If $aArray[$iStart][$iColumn] > $vValue Or $aArray[$iEnd][$iColumn] < $vValue Then Return SetError(2, 0, -1)
            ; Search
            While $iStart <= $iMid And Not ($vValue == $aArray[$iMid][$iColumn])
                If $vValue < $aArray[$iMid][$iColumn] Then
                    $iEnd = $iMid - 1
                Else
                    $iStart = $iMid + 1
                EndIf
                $iMid = Int(($iEnd + $iStart) / 2)
            WEnd
            If $iStart > $iEnd Then Return SetError(3, 0, -1) ; Entry not found
        Case Else
            Return SetError(5, 0, -1)
    EndSwitch
    Return $iMid
EndFunc   ;==>_ArrayBinarySearch

Output:

--> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop
Index 0: a_ausser
Index 1: a_außer
Index 2: b_ausser
Index 3: b_außer
Index 4: c_ausser
Index 5: c_außer
BinarySearchIndex: 3 <-- must be Index 3 - b_außer
BinarySearchIndex: 2 <-- must be Index 2 - b_ausser
+>09:37:17 AutoIt3.exe ended.rc:0

Here is the correct item with Index 3 found.

 

Only two lines have little changes:

line 25 in function:
Original: While $iStart <= $iMid And  $vValue <> $Array[$iMid]
FIX: While $iStart <= $iMid And Not ($vValue == $Array[$iMid])
line 39 in function:
Original: While $iStart <= $iMid And $vValue <> $aArray[$iMid][$iColumn])
FIX: While $iStart <= $iMid And Not ($vValue == $aArray[$iMid][$iColumn])

 

Please check my little bugfix and check in in the repository for the next release.

Edited by HHS
  • Like 1

Share this post


Link to post
Share on other sites
czardas

Thanks for reporting the bug. Unfortunately your fix has an issue: this function is currently not case sensitive and therefore the change would be script breaking. Your suggestion would work with the addition of an extra case sensitivity parameter. There are probably other alternatives, but this seems to be the easiest solution to this problem. It's still not perfect.

Edited by czardas

Share this post


Link to post
Share on other sites
jchd

I believe it all depends on which options are used by the internal call to StringCompareW. Unicode can be misleading, but German usually consider ß to be equivalent to ss.


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)

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

  • Similar Content

    • DynamicRookie
      By DynamicRookie
      Hey there!
       
      Is there a way to detect movement only for 1 specific window?

      HWnd is not really working, it still detects movement in all the windows within the region

      This is my script:
       
      ;Checksum actual HotKeySet("{f2}", 'exit_') MsgBox(0, '', '0') Beep(500, 2000) $Hwnd = WinActive('') while 1 $Checksum = PixelChecksum(211, 650, 1094, 914, 1, $Hwnd) If PixelChecksum(211, 650, 1094, 914, 1, $Hwnd) <> $Checksum Then For $i = 1 To 100 Beep(1000, 50) Next MsgBox(0, '', 'New message!', 1) EndIf WEnd Func exit_() Beep(500, 1000) Exit 0 EndFunc I just want to check whenever a message comes because the app i use doesn't give notifications properly.

      Any help is really appreciated!
    • PramodR
      By PramodR
      Can you please see whats wrong im doing in the below code? i can read few registry entry but not all for eg, i am able to get value of "Shell" Key from the registry path  but not AutoAdminLogon which has the value of "1", is there any change i have to do to read numeric values?
       Global  $shello = RegRead ("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon","Shell" )
       ConsoleWrite("This is Hello"& $shello)
      above command returns proper value , but same command with AutoAdminLogon returns null as shown in below ? infact registry has the value of 1.
       Global  $shello = RegRead ("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon","AutoAdminLogon" )
       ConsoleWrite("This is Hello"& $shello)
    • Eminence
      By Eminence
      Hello,
      I've been searching on how to select the first row in my database which includes a time column based on the latest start_time date for today's date.
      This is my current code:
      Local $iCurrentDate = _Now() Local $sqlHandle = _dbOpen($sDbPath) Local $aResult, $iRows, $iCols _SQLite_GetTable2d($sqlHandle, "SELECT start_time FROM " & $srawDb & " ORDER BY datetime(start_time) DESC LIMIT 1", $aResult, $iRows, $iCols) _ArrayDisplay($aResult) _dbClose($sDbpath) What it does is it gets the first row entry in the database however it does not select the latest start_time entry in the database, it always select the first row. I've tried changing DESC to ASC to see if that will do it but the issue still remains. Any thoughts on this? Thanks in advance.
       
      *EDIT
      The date format in the database is by MM/DD/YYYY HH:MM:SS.
    • Trisha
      By Trisha
      Hello,
      I Have clicked on save as option to save a file, while doing that I need to rename a file appending with sysdate. I have searched in google find the below one line of code:
      FileMove("C:\somefile.txt", "C:\somefile1.txt"), When I am trying to append with sysdate. It is not happening. Please help me out  with the small issue.
    • TrashBoat
      By TrashBoat
      hey i would like to know if its possible to take a string like this
      $string = "onethousandninehundredeightyfive" and convert it into:
      $string = "one thousand nine hundred eighty five" i have something going on here but its no use
      $string = "onethousandninehundredeightyfive" Global $array[9] = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] Global $array1[19] = ['onethousand', 'twothousand', 'threethousand', 'fourthousand', 'fivethousand', 'sixthousand', 'seventhousand', 'eightthousand', 'ninethousand','tenthousand','hundred', 'twohundred', 'threehundred', 'fourhundred', 'fivehundred', 'sixhundred', 'sevenhundred', 'eighthundred', 'ninehundred'] MsgBox(0, 0, AddSpaces($string)) Func AddSpaces($string) Local $finalStr $length = StringLen($string) For $x = 0 To $length Local $trim = StringTrimRight($string, $x) For $h = 0 To 18 If $trim = $array1[$h] Then $finalStr = $finalStr & " " & $trim $string = StringTrimLeft($string, $h) $length = StringLen($string) EndIf Next For $z = 0 To 8 If $trim = $array[$z] Then $finalStr = $finalStr & " " & $trim $string = StringTrimLeft($string, $z) $length = StringLen($string) EndIf Next Next Return $finalStr EndFunc ;==>AddSpaces  
×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.