Jump to content

compare 2 arrays with 3 arrays as a result


Go to solution Solved by iamtheky,

Recommended Posts

Hi

has anyone created a script to compare 2 arrays like this : 

compare the 2 arrays

- the items that are only in array 1 go into a new array

- the items that are only in array 2 go into another new array

- the items that are in both arrays go into another new array

like this : 

Global $Compare1[10] = [1, 3, 5, 6, 7, 8, 9, 10, 11, 12]

Global $Compare2[10] = [1, 2, 3, 4, 5, 6, 8, 10, 12, 13]

$whatsLeftOfCompare1 = [7, 9, 11]

$whatsLeftOfCompare2 = [2, 4, 13]

$whatsInBoth = [1, 3, 5, 6, 8, 10, 12]

I want to use this to compare 2 arrays with Active Directory rights and check which rights users have in comon and which rights they have separatly.

if any anyone has created this before and would like to share it, I would appreciate it very much!

I was searching on the forum but I didn't find anything that looks like this and I'm not really sure how I could achieve this without using like 4 or  5 loops

Edited by colombeen
Link to comment
Share on other sites

  • Solution

#include <Array.au3>

Global $aCompare1[10] = [1, 3, 5, 6, 7, 8, 9, 10, 11, 12]
Global $aCompare2[10] = [1, 2, 3, 4, 5, 6, 8, 10, 12, 13]
Global $aBoth[0]

For $i = ubound($aCompare1) - 1 to 0 step -1
$iMatch = _ArraySearch($aCompare2 , $aCompare1[$i])
If $iMatch <> -1 then
    _ArrayAdd($aBoth , $aCompare1[$i])
    _ArrayDelete($aCompare1 , $i)
    _ArrayDelete($aCompare2, $iMatch)
EndIf
Next

For $i = ubound($aCompare2) - 1 to 0 step -1
$iMatch = _ArraySearch($aCompare1 , $aCompare2[$i])
If $iMatch <> -1 then
    _ArrayAdd($aBoth , $aCompare2[$i])
    _ArrayDelete($aCompare2 , $i)
    _ArrayDelete($aCompare1 , $iMatch)
EndIf
Next

_ArrayDisplay ($aBoth, "In Both")
_ArrayDisplay ($aCompare1, "Only in Compare 1")
_ArrayDisplay ($aCompare2, "Only in Compare 2")

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

Another way (boththose beat me to it!)...

#include <array.au3>

local $Compare1 = [1, 3, 5, 6, 7, 8, 9, 10, 11, 12]
local $Compare2 = [1, 2, 3, 4, 5, 6, 8, 10, 12, 13, 19, '', 'whatever']
local $Common[1]

for $1 = ubound($Compare1) - 1 to 0 step -1
    for $2 = ubound($Compare2) - 1 to 0 step -1
        if $Compare1[$1] = $Compare2[$2] then
            redim $Common[ubound($Common)+1]
            $Common[ubound($Common)-1] = $Compare2[$2]
            _arraydelete($Compare1,$1)
            _arraydelete($Compare2,$2)
            ExitLoop
        EndIf
    Next
next

_arraydisplay($Compare1,'Compare1')
_arraydisplay($Compare2,'Compare2')
_arraydisplay($Common,'Common')

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

Link to comment
Share on other sites

So this is without redim, but when you are reading them out to whatever you are doing with the data preface it with:

If $array[$i] <> "" then ....

#include <Array.au3>

Global $aCompare1[10] = [1, 3, 5, 6, 7, 8, 9, 10, 11, 12]
Global $aCompare2[10] = [1, 2, 3, 4, 5, 6, 8, 10, 12, 13]
Global $aBoth[ubound($aCompare1) * 2]

Global $x = 0

For $i = ubound($aCompare1) - 1 to 0 step -1
$iMatch = _ArraySearch($aCompare2 , $aCompare1[$i])
If $iMatch <> -1 then
    $aBoth[$x] = $aCompare1[$i]
    $aCompare1[$i] = ""
    $aCompare2[$iMatch] = ""
    $x += 1
EndIf
Next

For $i = ubound($aCompare2) - 1 to 0 step -1
$iMatch = _ArraySearch($aCompare1 , $aCompare2[$i])
If $iMatch <> -1 then
    $aBoth[$x] = $aCompare2[$i]
    $aCompare2[$i] = ""
    $aCompare1[$iMatch] = ""
    $x += 1
EndIf
Next

_ArrayDisplay ($aCompare1, "Only in Compare 1")
_ArrayDisplay ($aCompare2, "Only in Compare 2")
_ArrayDisplay ($aBoth, "In Both") 

Or someone smrt will come clean up the blanks all fancy like.

Edited by boththose

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

do not know if is to be considered a bug or what, but bothdhose way fails if duplicate values are present in an array (because it says only in array1 while it's in both. for example double the number 10 in first array)

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

Here's one way I'd do it. I'm sure the comparisons could be done better, and getting rid of _ArraySearch would probably help too.

I used _ArrayShuffle so that I could make sure it would find the proper duplicates/unique items no matter what order they were in the arrays.

#include <Array.au3>
Global $Compare1[10] = [1, 3, 5, 6, 7, 8, 9, 10, 11, 12]
_ArrayShuffle($Compare1)

Global $Compare2[10] = [1, 2, 3, 4, 5, 6, 8, 10, 12, 13]
_ArrayShuffle($Compare2)


Global $whatsLeftOfCompare1[UBound($Compare1)]

Global $whatsLeftOfCompare2[UBound($Compare2)]

Global $whatsInBoth[100]
Global $K = 0, $L = 0
For $I = 0 To UBound($Compare1) - 1
    _ArraySearch($Compare2, $Compare1[$I])
    If Not @error Then
        $whatsInBoth[$K] = $Compare1[$I]
        $K += 1
    Else
        $whatsLeftOfCompare1[$L] = $Compare1[$I]
        $whatsLeftOfCompare2[$L] = $Compare2[$I]
        $L += 1
    EndIf
Next
$L = 0
For $I = 0 To UBound($Compare2) - 1
    _ArraySearch($Compare1, $Compare2[$I])
    If @error Then
        $whatsLeftOfCompare2[$L] = $Compare2[$I]
        $L += 1
    EndIf
Next
ReDim $whatsInBoth[$K]
ReDim $whatsLeftOfCompare1[$L]
ReDim $whatsLeftOfCompare2[$L]
_ArrayDisplay($whatsInBoth, "$whatsInBoth")
_ArrayDisplay($whatsLeftOfCompare1, "$whatsLeftOfCompare1")
_ArrayDisplay($whatsLeftOfCompare2, "$whatsLeftOfCompare2")

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

nah no bug, there are many cases where that will have to be modified it was just a crude example, a couple i have found are:

1) if there is dupes in the same array, or the potential, you get Chimps result, I would run arrayunique on them first if feasible.

       

2) if there are a different number of items in the arrays then one of the loops will blow up, as i am using the ubound of the target

      2a)  If there are dupes in the same array, and you perform the delete right after you find them (in the same fashion as the other arraysearch-->arraydelete, rather than using arrayunique), thus redimming and creating arrays of two different sizes, same explosion.

Edited by boththose

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

It seems that there are no issues using Scripting.Dictionary

#include <Array.au3>

Local $a[11] = [1, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12]
Local $b[12] = [1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14]

Local $sda = ObjCreate("Scripting.Dictionary")
Local $sdb = ObjCreate("Scripting.Dictionary")
Local $sdc = ObjCreate("Scripting.Dictionary")

For $i In $a
    $sda.Item($i) 
Next
For $i In $b
    $sdb.Item($i)
Next

For $i In $a
    If $sdb.Exists($i) Then $sdc.Item($i)
Next
$asd3 = $sdc.Keys() 

For $i In $asd3
    If $sda.Exists($i) Then $sda.Remove($i)
    If $sdb.Exists($i) Then $sdb.Remove($i)
Next
$asd1 = $sda.Keys()
$asd2 = $sdb.Keys()

_ArrayDisplay($asd1, "$asd1")
_ArrayDisplay($asd2, "$asd2")
_ArrayDisplay($asd3, "$asd3")
Link to comment
Share on other sites

That is beautiful, "advantages of scripting.dictionary over array functions" totally needs its own thread.

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

 

It seems that there are no issues using Scripting.Dictionary

 

In this case it works out as the scripting dictionary overwrites the duplicate key...

#include <Array.au3>

Local $a[11] = [1, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12]
Local $b[12] = [1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14]

Local $sda = ObjCreate("Scripting.Dictionary")
Local $sdb = ObjCreate("Scripting.Dictionary")
Local $sdc = ObjCreate("Scripting.Dictionary")

For $i In $a
    $sda.Item($i)
Next
For $i In $b
    $sdb.Item($i)
Next

; --------------------------------------
$aKeys = $sdb.Keys()
For $i = 0 To ubound($aKeys) -1
  ConsoleWrite($aKeys[$i] & @CRLF)
Next
;---------------------------------------

For $i In $a
    If $sdb.Exists($i) Then $sdc.Item($i)
Next
$asd3 = $sdc.Keys()

For $i In $asd3
    If $sda.Exists($i) Then $sda.Remove($i)
    If $sdb.Exists($i) Then $sdb.Remove($i)
Next
$asd1 = $sda.Keys()
$asd2 = $sdb.Keys()

_ArrayDisplay($asd1, "$asd1")
_ArrayDisplay($asd2, "$asd2")
_ArrayDisplay($asd3, "$asd3")

@boththose - I agree, for me personally anyway, when I stopped using VBS I also stopped using the scripting dictionary.  As mikell demonstated it may be time to start looking at it as another alternative.

kylomas

Edited by 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

Link to comment
Share on other sites

no claim of improvement, just another one
this returns results in a 2D array
col1 contains values contained only in first array, col2 those contained only in the second one, and col3 in both

#include <Array.au3>
Local $a[11] = [1, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12]
Local $b[12] = [1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14]

_ArrayDisplay(_Separate($a, $b))

Func _Separate(ByRef $in0, ByRef $in1)
    $in0 = _ArrayUnique($in0, 0, Default, Default, 0)
    $in1 = _ArrayUnique($in1, 0, Default, Default, 0)
    Local $z[2] = [UBound($in0), UBound($in1)], $low = 1 * ($z[0] > $z[1]), $aTemp[$z[Not $low]][3], $aOut = $aTemp, $aNdx[3]
    For $i = 0 To $z[Not $low] - 1
        If $i < $z[0] Then $aTemp[$i][0] = $in0[$i]
        If $i < $z[1] Then $aTemp[$i][1] = $in1[$i]
    Next
    For $i = 0 To $z[$low] - 1
        $x = _ArrayFindAll($aTemp, $aTemp[$i][$low], 0, 0, 1, 0, Not $low)
        If Not @error Then ; both
            For $j = 0 To UBound($x) - 1
                $aTemp[$x[$j]][2] = 1
            Next
            $aOut[$aNdx[2]][2] = $aTemp[$i][$low]
            $aNdx[2] += 1
        Else ; only in $low
            $aOut[$aNdx[$low]][$low] = $aTemp[$i][$low]
            $aNdx[$low] += 1
        EndIf
    Next
    For $i = 0 To $z[Not $low] - 1
        If $aTemp[$i][2] <> 1 Then
            $aOut[$aNdx[Not $low]][Not $low] = $aTemp[$i][Not $low]
            $aNdx[Not $low] += 1
        EndIf
    Next
    ReDim $aOut[_ArrayMax($aNdx)][3]
    Return $aOut
EndFunc   ;==>_Separate
Edited by Chimp

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

  • 3 years later...

*

Edited by iamtheky

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Link to comment
Share on other sites

  • 5 years later...

I needed such a function, but it was necessary to compare the values in stilts in certain rows.

I decided to make a universal function that compares both 1D and 2D values by columns or rows

By default, all values are compared as strings and optionally as numbers.

#include <Array.au3>

Local $Array1[2][12] = [[0,0,0,0,0,0,0,0,0,0,0,0],["TA",1,3,5,17,6,7,8,9,10,11,"MG"]]
Local $Array2[10][2] = [[1,0], [2,0], [2,0], [3,0], [4,0], [5,0], [6,0], [8,0], [10,0], ["MG",0]]
Local $aExRet = _ArrayCompare($Array1, $Array2, 0, 1, 2, 0, 0, 1, 0, 1)
_ArrayDisplay($aExRet)

Dim $Array1[14] = [1,"ZU",3,5,17,6,7,8,"GH",10,11,12]
Dim $Array2[12][2] = [[0,1], [0,1], [0,3], [0,5], [0,17], [0,6], [0,7], [0,"GH"], [0,9], [0,10], [0,11], [0,12]]
Local $aExRet = _ArrayCompare($Array1, $Array2, 0, 0, 1, 0, 1, 1, 0, 1)
_ArrayDisplay($aExRet)


Func _ArrayCompare($Array1, _ ; Array1 zum Abgleich
    Const ByRef $Array2, _ ; Array2 zum Abgleich
    $iStr1 = 0, _ ; Startindex für Array1
    $i1rc = 0, _ ; Param. für Array1; Spalte von 1 oder 2D Array1 // Zeile von 2D wenn $iRg1 = 2
    $iRg1 = 1, _ ; Param. für Array1; nur 1 oder 2; Bei 1 wird in allen Zeilen gesucht, bei 2 in allen Spalten
    $iStr2 = 0, _ ; Startindex für Array2
    $i2rc = 0, _ ; Param. für Array2; Spalte von 1 oder 2D Array2 // Zeile von 2D wenn $iRg1 = 2
    $iRg2 = 1, _ ; Param. für Array2; nur 1 oder 2; Bei 1 wird in allen Zeilen gesucht, bei 2 in allen Spalten
    $iDig = 0, _ ; 0 => alle Werte werden als String vergliechen; wenn 1 als Zahlen
    $iRtS = 1) ; 1 => ein 2D-Array mit dem Ergebnis für [x][0]-$Array1, [x][1]-$Array1 und [x][2]-Spalte mit allen vorhandenen in beiden Arrays
    ; ^^^^^ wenn 0 => ohne Spalte [x][2]-Spalte mit allen vorhandenen in beiden Arrays
    If Not IsArray($Array1) Or Not IsArray($Array2) Then Return SetError(-1)

    If ($iRg1 > 2) Or ($iRg1 < 1) Then Return SetError(-3)

    If ($iRg2 > 2) Or ($iRg2 < 1) Then Return SetError(-4)

    Local $iDmsA = UBound($Array1, 0)
    Local $iDmsB = UBound($Array2, 0)
    If ($iRg1 = 2 And $iDmsA = 1) Or ($iRg2 = 2 And $iDmsB = 1) Then Return SetError(-5)

    Local $nUb1 = UBound($Array1, $iRg1)
    Local $nUb2 = UBound($Array2, $iRg2)
    Local $oDic1 = ObjCreate("Scripting.Dictionary")
    Local $oDic2 = ObjCreate("Scripting.Dictionary")
    Local $oDic3 = ObjCreate("Scripting.Dictionary")
    For $iN = $iStr1 To $nUb1 -1
        If $iDmsA = 1 Then
            $Array1[$iN] = ($iDig ? (Number($Array1[$iN])) : (String($Array1[$iN])))
            $oDic1.Item($Array1[$iN])
        Else
            If $iRg1 = 1 Then
                $Array1[$iN][$i1rc] = ($iDig ? (Number($Array1[$iN][$i1rc])) : (String($Array1[$iN][$i1rc])))
                $oDic1.Item($Array1[$iN][$i1rc])
            Else
                $Array1[$i1rc][$iN] = ($iDig ? (Number($Array1[$i1rc][$iN])) : (String($Array1[$i1rc][$iN])))
                $oDic1.Item($Array1[$i1rc][$iN])
            EndIf
        EndIf
    Next
    For $iN = $iStr2 To $nUb2 -1
        If $iDmsB = 1 Then
            $oDic2.Item($iDig ? (Number($Array2[$iN])) : (String($Array2[$iN])))
        Else
            If $iRg2 = 1 Then
                $oDic2.Item($iDig ? (Number($Array2[$iN][$i2rc])) : (String($Array2[$iN][$i2rc])))
            Else
                $oDic2.Item($iDig ? (Number($Array2[$i2rc][$iN])) : (String($Array2[$i2rc][$iN])))
            EndIf
        EndIf
    Next
    For $iN = $iStr1 To $nUb1 -1
        If $iDmsA = 1 Then
            If $oDic2.Exists($Array1[$iN]) Then
                $oDic3.Item($Array1[$iN])
            EndIf
        Else
            If $iRg1 = 1 Then
                If $oDic2.Exists($Array1[$iN][$i1rc]) Then
                    $oDic3.Item($Array1[$iN][$i1rc])
                EndIf
            Else
                If $oDic2.Exists($Array1[$i1rc][$iN]) Then
                    $oDic3.Item($Array1[$i1rc][$iN])
                EndIf
            EndIf
        EndIf
    Next
    Local $aRet3 = $oDic3.Keys()
    Local $nUb3 = UBound($aRet3)-1
    For $iN = 0 To $nUb3
        If $oDic1.Exists($aRet3[$iN]) Then
            $oDic1.Remove($aRet3[$iN])
        EndIf
        If $oDic2.Exists($aRet3[$iN]) Then
            $oDic2.Remove($aRet3[$iN])
        EndIf
    Next
    $oDic3.RemoveAll()

    Local $aRet1 = $oDic1.Keys()
    $nUb1 = UBound($aRet1)-1
    $oDic1.RemoveAll()
    Local $aRet2 = $oDic2.Keys()
    $nUb2 = UBound($aRet2)-1
    $oDic2.RemoveAll()
    If Not $iRtS Then
        $nUb3 = -1
    EndIf
    Local $nExUB = (($nUb1 > $nUb2) ? (($nUb1 > $nUb3) ? $nUb1 : $nUb3) : (($nUb2 > $nUb3) ? $nUb2 : $nUb3))
    Local $aExRet[$nExUB+1][($iRtS ? 3 : 2)]
    For $iN = 0 To $nExUB
        If $iN <= $nUb1 Then
            $aExRet[$iN][0] = $aRet1[$iN]
        EndIf
        If $iN <= $nUb2 Then
            $aExRet[$iN][1] = $aRet2[$iN]
        EndIf
        If $iN <= $nUb3 Then
            $aExRet[$iN][2] = $aRet3[$iN]
        EndIf
    Next
    Return $aExRet
EndFunc

 

Edited by Norm73
Link to comment
Share on other sites

Norm73, glad you found a solution for your need :)
I never saw this old thread before today, so I studied just now mikell's good solution (based on Scripting Dictionary)

It seems to me that mikell's script can be improved, by the use of 3 loops instead of 4, with the same result, like this :

#include <Array.au3>

Local $a[11] = [1, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12] ; some duplicate values (1 found twice)
Local $b[12] = [1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14] ; some duplicate values (2 found twice)

Local $sda = ObjCreate("Scripting.Dictionary")
Local $sdb = ObjCreate("Scripting.Dictionary")
Local $sdc = ObjCreate("Scripting.Dictionary")

For $i In $a
    $sda.Item($i) ; unique keys
Next

For $i In $b
    $sdb.Item($i) ; unique keys
Next

For $i In $sda
    If $sdb.Exists($i) Then
        $sdc.Item($i)
        $sda.Remove($i)
        $sdb.Remove($i)
    EndIf
Next

$asd1 = $sda.Keys()
$asd2 = $sdb.Keys()
$asd3 = $sdc.Keys()

_ArrayDisplay($asd1, "$asd1") ; 7, 9, 11
_ArrayDisplay($asd2, "$asd2") ; 2, 4, 13, 14
_ArrayDisplay($asd3, "$asd3") ; 1, 3, 5, 6, 8, 10, 12

Another thing we could think about is : should the 3rd loop be...

For $i In $sda
; or
For $i In $sdb

...I think it depends on the number of elements in each dictionary. In our case they're nearly the same so it doesn't matter which one you'll choose, but imagine one dictionary got only 3 elements and the second dictionary got 10000 elements, then it seems quicker to execute the For...In loop 3 times (by using the shorter dictionary), instead of looping 10000 times by choosing the longer dictionary. Anyway, results will be same, no matter the dictionary you choose in the 3rd For...In loop

If you guys think something is wrong in this reworked script, please be kind to indicate it, thanks.

Link to comment
Share on other sites

pixelsearch  following and exploring your latest posts prompts me to share the results :)

; https://www.autoitscript.com/forum/topic/164728-compare-2-arrays-with-3-arrays-as-a-result/?do=findComment&comment=1534659
#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7

#include <Array.au3>

; I do 3 laps to compare
For $i = 1 To 3
    ConsoleWrite("- Round " & $i & " -----------------" & @CRLF)
    FuncSpeedTest('_Dictionary()')
    FuncSpeedTest('_Map()')
Next

;--------------------------------------------------------------------------------------------------------------------------------
Func _Map()
    Local $a[11] = [1, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12]     ; some duplicate values (1 found twice)
    Local $b[12] = [1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14] ; some duplicate values (2 found twice)

    Local $mda[]
    Local $mdb[]
    Local $mdc[]

    For $i In $a
        $mda[$i] = $i ; unique keys
    Next

    For $i In $b
        $mdb[$i] = $i ; unique keys
    Next

    Local $ada = MapKeys($mda)

    For $vKey In $ada
        If MapExists($mdb, $vKey) Then
            $mdc[$vKey] = $vKey
            MapRemove($mda, $vKey)
            MapRemove($mdb, $vKey)
        EndIf
    Next

    Local $asd1 = MapKeys($mda)
    Local $asd2 = MapKeys($mdb)
    Local $asd3 = MapKeys($mdc)

    _Print($asd1, "$asd1")
    _Print($asd2, "$asd2")
    _Print($asd3, "$asd3")

EndFunc   ;==>_Map
;--------------------------------------------------------------------------------------------------------------------------------
Func _Dictionary()
    Local $a[11] = [1, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12] ; some duplicate values (1 found twice)
    Local $b[12] = [1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 13, 14] ; some duplicate values (2 found twice)

    Local $sda = ObjCreate("Scripting.Dictionary")
    Local $sdb = ObjCreate("Scripting.Dictionary")
    Local $sdc = ObjCreate("Scripting.Dictionary")

    For $i In $a
        $sda.Item($i) ; unique keys
    Next

    For $i In $b
        $sdb.Item($i) ; unique keys
    Next

    For $i In $sda
        If $sdb.Exists($i) Then
            $sdc.Item($i)
            $sda.Remove($i)
            $sdb.Remove($i)
        EndIf
    Next

    Local $asd1 = $sda.Keys()
    Local $asd2 = $sdb.Keys()
    Local $asd3 = $sdc.Keys()

    _Print($asd1, "$asd1")
    _Print($asd2, "$asd2")
    _Print($asd3, "$asd3")

EndFunc   ;==>_Dictionary
;--------------------------------------------------------------------------------------------------------------------------------
Func _Print(ByRef $aArray, $sTitle)
    Local $sTxt = ""
    For $i = 0 To UBound($aArray) - 1
        $sTxt &= $aArray[$i] & ", "
    Next
    $sTxt = StringTrimRight($sTxt, 2)
    ConsoleWrite($sTitle & ": " & $sTxt & @CRLF)
EndFunc   ;==>_Print
;--------------------------------------------------------------------------------------------------------------------------------
Func FuncSpeedTest($sExecute)
    Local $hTimer = TimerInit()
    Execute($sExecute)
    ConsoleWrite($sExecute & " processed in: " & TimerDiff($hTimer) & " ms " & @LF & @LF)
EndFunc   ;==>FuncSpeedTest
;--------------------------------------------------------------------------------------------------------------------------------

if I did it right and I'm not missing anything, the difference was quite significant (considering that the sample is quite small)

Edited by ioa747

I know that I know nothing

Link to comment
Share on other sites

@ioa747 thanks for the speed test between Map and Scripting.Dictionary

3 hours ago, ioa747 said:

if I did it right and I'm not missing anything, the difference was quite significant (considering that the sample is quite small)

What about we try the tests on larger arrays ?
Below is your reworked speed test. Now we can define the number of rows in each array with this line :

Local $iRows = 50 ; after this 1st test, try other values for $iRow, like 5000, then 10000, 20000...

The 2 arrays generated for each test will be exactly the same (because of the SRandom instruction, for example 4 for the 1st array, 5 for the 2nd array)

Could you please run this reworked script, first with the indicated value (50, it will ConsoleWrite the results, just for checking) . Then re-run it with $iRows = 5000, 10000... (no more ConsoleWrite of values in these cases, just the timer difference)

Does the Map part is still quicker than the Scripting.Dictionary part, when the arrays grow bigger ?
Thanks

; AutoIt 3.3.16.1 (Map)
; Comparing speed between Map and Scripting.Dictionary

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7

#include <Array.au3>

Local $iRows = 50 ; after this 1st test, try other values for $iRow, like 5000, then 10000, 20000...
ConsoleWrite("$iRows = " & $iRows & @crlf & @crlf)

; I do 3 laps to compare
For $i = 1 To 3
    ConsoleWrite("- Round " & $i & " -----------------" & @CRLF)
    FuncSpeedTest('_Dictionary($iRows)')
    FuncSpeedTest('_Map($iRows)')
Next

;--------------------------------------------------------------------------------------------------------------------------------
Func _Map($iRows)
    Local $a[$iRows], $b[$iRows]
    GenerateArrayInt($a, $iRows, 4) ; seed value for random number generation (to generate exactly the same array for each test)
    GenerateArrayInt($b, $iRows, 5) ; ditto

    Local $mda[]
    Local $mdb[]
    Local $mdc[]

    For $i In $a
        $mda[$i] = $i ; unique keys
        ; $mda[$i] = Null ; no need to associate a value to each unique key (to match the script dictionary test)
    Next
    ; _ArrayDisplay(_Map2D($mda), "$mda : Map Keys & Values") ; comment out this line during tests !

    For $i In $b
        $mdb[$i] = $i ; unique keys
    Next

    Local $ada = MapKeys($mda)

    For $vKey In $ada
        If MapExists($mdb, $vKey) Then
            $mdc[$vKey] = $vKey
            MapRemove($mda, $vKey)
            MapRemove($mdb, $vKey)
        EndIf
    Next

    Local $asd1 = MapKeys($mda)
    Local $asd2 = MapKeys($mdb)
    Local $asd3 = MapKeys($mdc)

    If $iRows <= 50 Then _Print($asd1, "$asd1")
    If $iRows <= 50 Then _Print($asd2, "$asd2")
    If $iRows <= 50 Then _Print($asd3, "$asd3")

EndFunc   ;==>_Map
;--------------------------------------------------------------------------------------------------------------------------------
Func _Dictionary($iRows)
    Local $a[$iRows], $b[$iRows]
    GenerateArrayInt($a, $iRows, 4) ; seed value for random number generation (to generate exactly the same array for each test)
    GenerateArrayInt($b, $iRows, 5) ; ditto

    Local $sda = ObjCreate("Scripting.Dictionary")
    Local $sdb = ObjCreate("Scripting.Dictionary")
    Local $sdc = ObjCreate("Scripting.Dictionary")

    For $i In $a
        $sda.Item($i) ; unique keys
    Next

    For $i In $b
        $sdb.Item($i) ; unique keys
    Next

    For $i In $sda
        If $sdb.Exists($i) Then
            $sdc.Item($i)
            $sda.Remove($i)
            $sdb.Remove($i)
        EndIf
    Next

    Local $asd1 = $sda.Keys()
    Local $asd2 = $sdb.Keys()
    Local $asd3 = $sdc.Keys()

    If $iRows <= 50 Then _Print($asd1, "$asd1")
    If $iRows <= 50 Then _Print($asd2, "$asd2")
    If $iRows <= 50 Then _Print($asd3, "$asd3")

EndFunc   ;==>_Dictionary
;--------------------------------------------------------------------------------------------------------------------------------
Func _Print(ByRef $aArray, $sTitle)
    Local $sTxt = ""
    For $i = 0 To UBound($aArray) - 1
        $sTxt &= $aArray[$i] & ", "
    Next
    $sTxt = StringTrimRight($sTxt, 2)
    ConsoleWrite($sTitle & ": " & $sTxt & @CRLF)
EndFunc   ;==>_Print
;--------------------------------------------------------------------------------------------------------------------------------
Func FuncSpeedTest($sExecute)
    Local $hTimer = TimerInit()
    Execute($sExecute)
    ConsoleWrite($sExecute & " processed in: " & TimerDiff($hTimer) & " ms " & @LF & @LF)
EndFunc   ;==>FuncSpeedTest
;--------------------------------------------------------------------------------------------------------------------------------
Func GenerateArrayInt(ByRef $aArray, $iRows, $iSeed)
    SRandom($iSeed)
    For $i = 0 To $iRows - 1
        $aArray[$i] = Random(0, $iRows, 1) ; 1 to return integer values
    Next
EndFunc   ;==>GenerateArrayInt
;--------------------------------------------------------------------------------------------------------------------------------
Func _Map2D(Const ByRef $mMap)
    Local $aMapKeys = MapKeys($mMap)
    Local $aMap2D[Ubound($aMapKeys)][2]
    Local $iRow = - 1
    For $vKey In $aMapKeys
        $iRow += 1 ; 0+
        $aMap2D[$iRow][0] = $vKey
        $aMap2D[$iRow][1] = $mMap[$vKey]
    Next
    Return $aMap2D
EndFunc   ;==>_Map2D
;--------------------------------------------------------------------------------------------------------------------------------

 

Link to comment
Share on other sites

@ioa747 hello
You were right about the comparative speed between scripting dictionary and map
I'm just testing the precedent script on a win 11 laptop with 16Go ram (AMD Ryzen 7 5800H with Radeon Graphics, 3.20 GHz)

With 30000 elements, scripting dictionary takes 1s when map takes 0.5s (approx)
Then with 50000 or 100000 elements, it's the same kind of results : map always takes half the time than scripting dictionary

On a much slower PC with much less ram, it seems to be the opposite (scripting dictionary takes less time than map when the number of elements icrease)
As most people got today a quick laptop, then let's stick with your conclusion (unless somebody got a different opinion), so let's use Map instead of Scripting dictionary on recent computers.
 

Link to comment
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
 Share

  • Recently Browsing   0 members

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