D1Spartan

Array Comparison

12 posts in this topic

I've done some searching, both in the forums and in the include files, and have not found a way to compare 2 arrays to check for equality.  I have created a function (which I am willing to share if there is no way to do this currently), but I am wondering is there an existing function?  The following code illustrates what I am trying to accomplish, but the results aren't correct

Dim $array1 [2][2]
Dim $array2 [2][2]
$value = 0

; Populate Array
For $i = 0 To 1
   For $j = 0 To 1
      $array1[$i][$j] = $value
      $value += 1
   Next
Next

; $array1 is equal to $array2
$array2 = $array1

ConsoleWrite ("Should be TRUE" & @CRLF)
checkArray ()

; Change the first value to 42 to make the two arrays not equal
$array1[0][0] = 42

ConsoleWrite (@CRLF)

ConsoleWrite ("Should be FALSE" & @CRLF)
checkArray ()

Func checkArray ()
   ; Check for equality using the standard (AutoIt) equality check
   If $array2 = $array1 Then
      ConsoleWrite ("Standard Check: True" & @CRLF)
   Else
      ConsoleWrite ("Standard Check: False" & @CRLF)
   EndIf

   ; Check for equality using the C Style (==) equality check
   If $array2 == $array1 Then
      ConsoleWrite ("C Style Check: True" & @CRLF)
   Else
      ConsoleWrite ("C Style Check: False" & @CRLF)
   EndIf

   ; Check for equality using for loops
   $result = True

   For $i = 0 To 1
      For $j = 0 To 1
         If $array1[$i][$j] <> $array2[$i][$j] Then
            $result = False
         EndIf
      Next
   Next

   ConsoleWrite ("For Loop Check: " & $result & @CRLF)
EndFunc

What this shows is that you can't check for equality between two arrays by saying either:

If $array1 = $array2

     -or-

If $array1 == $array2

Please let me know if I'm doing anything wrong, or if there is already a method to check this.

 

-D1Spartan

Share this post


Link to post
Share on other sites



D1Spartan,

As you have discovered there is no short way to check array equality. Whenever I have to do this I start by using UBound to check for equal size and then either loop through the arrays checking each element or (if the array is not too large) use _ArrayToString and do a simple comparison.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

Share this post


Link to post
Share on other sites

Melba,

Thanks for the confirmation.  The function I have created will take two arrays of any dimensional size (I have not checked where the limit of this is) and compare them for equality.  I think this may be a nice addition to the Array UDF that exists already.  I know you contributed to that UDF, so can you point me in the right direction to try to get it added?

-D1Spartan

Share this post


Link to post
Share on other sites

D1Spartan,

Quote

I have not checked where the limit of this is

From the Help file:

VAR_SUBSCRIPT_ELEMENTS:  16,777,216 - Maximum number of elements for an array
VAR_SUBSCRIPT_MAX:       64         - Maximum number of subscripts for an array
Quote

the right direction to try to get it added

Post what you have and let us take a look.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Melba,

I understand max values (knew they were in the help file, but didn't look them up again) but what I was referring to is the fact that my function uses recursion and I don't know what the limit is that AutoIt imposes to prevent a stack overflow (number of times a function can call itself, probably in the help file as well but haven't looked).

Also, are you suggesting just posting it here, on this post?  I'm fine with that if that is what you meant.

-D1Spartan

Edited by D1Spartan

Share this post


Link to post
Share on other sites

D1Spartan,

Quote

are you suggesting just posting it here

Yes.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

Share this post


Link to post
Share on other sites

Proposed _ArrayCompare function:

Func _ArrayCompare (Const ByRef $array1, Const ByRef $array2)
   ; Check Subscripts
   $array1NumDimensions = UBound ($array1, 0)
   $array2NumDimensions = UBound ($array2, 0)

   ; Static Variables
   Static $arrayMatch
   Static $evaluationString = ""
   Static $dimension = 0

   If $dimension = 0 Then
      If $array1NumDimensions <> $array2NumDimensions Then
         Return SetError (1, 0, False)
      EndIf

      If $array1NumDimensions = 0 Then
         Return SetError (2, 0, False)
      EndIf
   EndIf

   Switch $dimension
      Case 0
         ; Start the iterations
         $arrayMatch = True
         $dimension = 1
         _ArrayCompare ($array1, $array2)
         $dimension = 0
      Case Else
         ; Save string to revert back
         $oldString = $evaluationString

         For $i = 0 To (UBound ($array1, $dimension) - 1)
            ; Add dimension to the string
            $evaluationString &= "[" & $i & "]"

            If $dimension = $array1NumDimensions Then
               ; Evaluate the string
               $arrayMatch = Execute ("$array1" & $evaluationString & " = $array2" & $evaluationString)

               ConsoleWrite ($evaluationString & " : " & $arrayMatch & @CRLF)
            Else
               ; Call the function for the next dimension
               $dimension += 1
               _ArrayCompare ($array1, $array2)
               $dimension -= 1
            EndIf

            ; Revert to old string
            $evaluationString = $oldString

            ; Dump out after the first mismatch
            If $arrayMatch = False Then
               ExitLoop
            EndIf
         Next
      EndSwitch
   Return $arrayMatch
EndFunc

Let me know what you think, or if you have questions.

-D1Spartan

Share this post


Link to post
Share on other sites

D1Spartan,

We are never too keen on recursive functions - too much room for error and confusion - plus we limit the built-in functions to a max of 2 dimensions (or else they get too unwieldy) which means we do not normally need it.

I did some testing to see if your method was faster than those I suggested above - with the following results (times in secs):

Method       100x100      1000x100     1000x1000   < array aize

D1Spartan    0.39         2.87         28.5          recursive

M23 Mode: 0  0.04         0.46         4.5           each element compare

M23 Mode: 1  0.07         3.69         40.0          string row compare

M23 Mode: 2  0.07         0.97         40.0          string column compare

M23 Mode: 3  0.14         1.39        146.9          string whole array compare

Here is the script I used if you want to try on your machine:

#include <AutoItConstants.au3>
#include <Array.au3>

ConsoleWrite("Creating arrays" & @CRLF)

Local $aArray_1[100][100]
For $i = 0 To 99
    For $j = 0 To 99
        $aArray_1[$i][$j] = "Row " & $i & " - Col " & $j
    Next
Next
$aArray_2 = $aArray_1

ConsoleWrite("Comparing" & @CRLF)

$nBegin = TimerInit()
$iRet = _ArrayCompare_Spartan($aArray_1, $aArray_2)
ConsoleWrite("Spartan: " & TimerDiff($nBegin) & @CRLF)
If $iRet = 1 Then
    ConsoleWrite("Match" & @CRLF)
EndIf

$nBegin = TimerInit()
$iRet = _ArrayCompare_M23($aArray_1, $aArray_2)
ConsoleWrite("M23 0: " & TimerDiff($nBegin) & @CRLF)
If $iRet = 1 Then
    ConsoleWrite("Match" & @CRLF)
EndIf

$nBegin = TimerInit()
$iRet = _ArrayCompare_M23($aArray_1, $aArray_2, 1)
ConsoleWrite("M23 1: " & TimerDiff($nBegin) & @CRLF)
If $iRet = 1 Then
    ConsoleWrite("Match" & @CRLF)
EndIf

$nBegin = TimerInit()
$iRet = _ArrayCompare_M23($aArray_1, $aArray_2, 2)
ConsoleWrite("M23 2: " & TimerDiff($nBegin) & @CRLF)
If $iRet = 1 Then
    ConsoleWrite("Match" & @CRLF)
EndIf

$nBegin = TimerInit()
$iRet = _ArrayCompare_M23($aArray_1, $aArray_2, 3)
ConsoleWrite("M23 3: " & TimerDiff($nBegin) & @CRLF)
If $iRet = 1 Then
    ConsoleWrite("Match" & @CRLF)
EndIf

Func _ArrayCompare_Spartan (Const ByRef $array1, Const ByRef $array2)
   ; Check Subscripts
   $array1NumDimensions = UBound ($array1, 0)
   $array2NumDimensions = UBound ($array2, 0)

   ; Static Variables
   Static $arrayMatch
   Static $evaluationString = ""
   Static $dimension = 0

   If $dimension = 0 Then
      If $array1NumDimensions <> $array2NumDimensions Then
         Return SetError (1, 0, False)
      EndIf

      If $array1NumDimensions = 0 Then
         Return SetError (2, 0, False)
      EndIf
   EndIf

   Switch $dimension
      Case 0
         ; Start the iterations
         $arrayMatch = True
         $dimension = 1
         _ArrayCompare_Spartan ($array1, $array2)
         $dimension = 0
      Case Else
         ; Save string to revert back
         $oldString = $evaluationString

         For $i = 0 To (UBound ($array1, $dimension) - 1)
            ; Add dimension to the string
            $evaluationString &= "[" & $i & "]"

            If $dimension = $array1NumDimensions Then
               ; Evaluate the string
               $arrayMatch = Execute ("$array1" & $evaluationString & " = $array2" & $evaluationString)

               ;ConsoleWrite ($evaluationString & " : " & $arrayMatch & @CRLF)
            Else
               ; Call the function for the next dimension
               $dimension += 1
               _ArrayCompare_Spartan ($array1, $array2)
               $dimension -= 1
            EndIf

            ; Revert to old string
            $evaluationString = $oldString

            ; Dump out after the first mismatch
            If $arrayMatch = False Then
               ExitLoop
            EndIf
         Next
      EndSwitch
   Return $arrayMatch
EndFunc

Func _ArrayCompare_M23(Const ByRef $aArray1, Const ByRef $aArray2, $iMode = 0)

    ; Check if arrays
    If Not(IsArray($aArray1)) Or Not(IsArray($aArray2)) Then
        Return SetError(1, 0, 0)
    EndIf

    ; Check if same number of dimensions
    $iDims = UBound($aArray1, $UBOUND_DIMENSIONS)
    If $iDims <> UBound($aArray2, $UBOUND_DIMENSIONS) Then
        Return SetError(2, 0, 0)
    EndIf

    ; Check if same size
    $iRows = UBound($aArray1, $UBOUND_ROWS)
    $iCols = UBound($aArray1, $UBOUND_COLUMNS)
    If $iRows <> UBound($aArray2, $UBOUND_ROWS) Or $iCols <> UBound($aArray2, $UBOUND_COLUMNS) Then
        Return SetError(3, 0, 0)
    EndIf

    Local $sString_1, $sString_2

    Switch $iMode

        Case 0 ; Compare each element
            For $i = 0 To $iRows - 1
                For $j = 0 To $iCols - 1
                    If $aArray1[$i][$j] <> $aArray1[$i][$j] Then
                        Return SetError(4, 0, 0)
                    EndIf
                Next
            Next

        Case 1 ; Convert rows to strings
            For $i = 0 To $iRows - 1
                For $j = 0 To $iCols - 1
                    $sString_1 &= $aArray1[$i][$j]
                    $sString_2 &= $aArray2[$i][$j]
                Next
                If $sString_1 <> $sString_2 Then
                    Return SetError(4, 0, 0)
                EndIf
            Next

        Case 2 ; Convert columnss to strings
            For $j = 0 To $iCols - 1
                For $i = 0 To $iRows - 1
                    $sString_1 &= $aArray1[$i][$j]
                    $sString_2 &= $aArray2[$i][$j]
                Next
                If $sString_1 <> $sString_2 Then
                    Return SetError(4, 0, 0)
                EndIf
            Next

        Case 3 ; Convert whole array to string
            If _ArrayToString($aArray1) <> _ArrayToString($aArray2) Then
                Return SetError(4, 0, 0)
            EndIf

    EndSwitch

    ; Looks as if they match
    Return 1

EndFunc

From those results, it looks as if the "each element compare" method is by far the fastest in all cases, but especially when the array is of any size, although the "full array string" method is not too bad when used on smaller arrays. So I do not think we will be adopting your suggested function into the standard library.

However, please do not get discouraged by my response. We are always interested in seeing new ways of doing things - I have just been testing a proposal for a new way to sort 2D arrays which is very much faster than the current algorithm and which will be incorporated into the standard library very soon. So please do keep on with the good ideas.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

Share this post


Link to post
Share on other sites

Melba,

Thank you for the response.  When I ran it on my work laptop (Dell, nothing special) the ratios were a bit different.  Regardless, I can understand why (given the limitation of 2 dimensions) this method would not be incorporated into the standard library.  I'm not discouraged by the way.  My function fits my purposes, and I figured if it could help anyone else, great.

Thanks again for looking at the code.

-D1Spartan

Share this post


Link to post
Share on other sites

A small tip for you D1Spartan. For a case sensitive <> comparison you can use this.

#include <MsgBoxConstants.au3>

Local $sStr1 = 'hello world'
Local $sStr2 = 'HELLO WORLD'

If $sStr1 <> $sStr2 Then ; case insensitive
    MsgBox($MB_OK, "case insensitive", 'strings are not equal')
ElseIf Not ($sStr1 == $sStr2) Then ; case sensitive comparison
    MsgBox($MB_OK, "case sensitive", 'strings are not exactly equal')
EndIf

 

Share this post


Link to post
Share on other sites

jguinch,

I have nothing against recursion per se - but I do try and avoid it if possible as using it so often ends in tears unless you are very, very careful.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

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