#2563 closed Feature Request (Rejected)
UDF - _ArrayUnique - proposal
Reported by: | mlipok | Owned by: | |
---|---|---|---|
Milestone: | Component: | Standard UDFs | |
Version: | Severity: | None | |
Keywords: | Cc: |
Description
now is:
Func _ArrayUnique(Const ByRef $aArray, $iColumn = Default, $iBase = Default, $iCase = Default, $iFlags = Default) If $iColumn = Default Then $iColumn = 1 If $iBase = Default Then $iBase = 0 If $iCase = Default Then $iCase = 0 If $iFlags = Default Then $iFlags = 1 ; Start bounds checking If UBound($aArray) = 0 Then Return SetError(1, 0, 0) ; Check if array is empty, or not an array ; $iBase can only be 0 or 1, if anything else, return with an error If $iBase < 0 Or $iBase > 1 Or (Not IsInt($iBase)) Then Return SetError(2, 0, 0) If $iCase < 0 Or $iCase > 1 Or (Not IsInt($iCase)) Then Return SetError(2, 0, 0) If $iFlags < 0 Or $iFlags > 1 Or (Not IsInt($iFlags)) Then Return SetError(4, 0, 0) Local $iDims = UBound($aArray, 0), $iNumColumns = UBound($aArray, 2) If $iDims > 2 Then Return SetError(3, 0, 0) ; checks the given dimension is valid If ($iColumn < 1) Or ($iNumColumns = 0 And ($iColumn - 1 > $iNumColumns)) Or ($iNumColumns > 0 And ($iColumn > $iNumColumns)) Then Return SetError(3, 0, 0) ; make $iColumn an array index, note this is ignored for 1D arrays $iColumn -= 1 ; create dictionary Local $oD = ObjCreate("Scripting.Dictionary") ; compare mode for strings ; 0 = binary, which is case sensitive ; 1 = text, which is case insensitive ; this expression forces either 1 or 0 $oD.CompareMode = Number(Not $iCase) Local $vElem ; walk the input array For $i = $iBase To UBound($aArray) - 1 If $iDims = 1 Then ; 1D array $vElem = $aArray[$i] Else ; 2D array $vElem = $aArray[$i][$iColumn] EndIf ; add key to dictionary ; NOTE: accessing the value (.Item property) of a key that doesn't exist creates the key :) ; keys are guaranteed to be unique $oD.Item($vElem) Next ; ; return the array of unique keys If BitAND($iFlags, 1) = 1 Then Local $aTemp = $oD.Keys() _ArrayInsert($aTemp, 0, $oD.Count) Return $aTemp Else Return $oD.Keys() EndIf EndFunc ;==>_ArrayUnique
proposal:
Func _ArrayUnique(Const ByRef $aArray, $iColumn = Default, $iBase = Default, $iCase = Default, $iFlags = Default) If $iColumn = Default Then $iColumn = 1 If $iBase = Default Then $iBase = 0 If $iCase = Default Then $iCase = 0 If $iFlags = Default Then $iFlags = 1 ; Start bounds checking Local $iUBound = UBound($aArray) If $iUBound = 0 Then Return SetError(1, 0, 0) ; Check if array is empty, or not an array ; $iBase can only be 0 or 1, if anything else, return with an error If $iBase < 0 Or $iBase > 1 Or (Not IsInt($iBase)) Then Return SetError(2, 0, 0) If $iCase < 0 Or $iCase > 1 Or (Not IsInt($iCase)) Then Return SetError(2, 0, 0) If $iFlags < 0 Or $iFlags > 1 Or (Not IsInt($iFlags)) Then Return SetError(4, 0, 0) Local $iDims = UBound($aArray, 0), $iNumColumns = UBound($aArray, 2) If $iDims > 2 Then Return SetError(3, 0, 0) ; checks the given dimension is valid If ($iColumn < 1) Or ($iNumColumns = 0 And ($iColumn - 1 > $iNumColumns)) Or ($iNumColumns > 0 And ($iColumn > $iNumColumns)) Then Return SetError(3, 0, 0) ; make $iColumn an array index, note this is ignored for 1D arrays $iColumn -= 1 ; create dictionary Local $oD = ObjCreate("Scripting.Dictionary") ; compare mode for strings ; 0 = binary, which is case sensitive ; 1 = text, which is case insensitive ; this expression forces either 1 or 0 $oD.CompareMode = Number(Not $iCase) Local $vElem ; walk the input array $iUBound -=1 For $i = $iBase To $iUBound If $iDims = 1 Then ; 1D array $vElem = $aArray[$i] Else ; 2D array $vElem = $aArray[$i][$iColumn] EndIf ; add key to dictionary ; NOTE: accessing the value (.Item property) of a key that doesn't exist creates the key :) ; keys are guaranteed to be unique $oD.Item($vElem) Next ; ; return the array of unique keys If BitAND($iFlags, 1) = 1 Then Local $aTemp = $oD.Keys() _ArrayInsert($aTemp, 0, $oD.Count) Return $aTemp Else Return $oD.Keys() EndIf EndFunc ;==>_ArrayUnique
changed:
Local $iUBound = UBound($aArray) If $iUBound = 0 Then Return SetError(1, 0, 0) ; Check if array is empty, or not an array
and
$iUBound -=1 For $i = $iBase To $iUBound
because: faster
Attachments (0)
Change History (10)
comment:1 Changed 11 years ago by mlipok
comment:3 Changed 11 years ago by AdmiralAlkex
- Summary changed from UDF - to UDF - _ArrayUnique - proposal
comment:4 Changed 11 years ago by BrewManNH
How much faster is it doing it this way?
comment:5 Changed 11 years ago by mlipok
RESULTS AutoIt 3.3.8.1:
>"C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.exe" /run /prod /ErrorStdOut /in "L:\TOOLs\Macro\ TEST\TEST ArrayUnique.au3" /UserParams +>14:57:33 Starting AutoIt3Wrapper v.2.1.3.2 SciTE v.3.3.7.0 ; Keyboard:00000415 OS:WIN_7/Service Pack 1 CPU:X64 OS:X64 Environment(Language:0415 Keyboard:00000415 OS:WIN_7/Service Pack 1 CPU:X64 OS:X64) >Running AU3Check (3.3.9.5) from:C:\Program Files (x86)\AutoIt3 +>14:57:33 AU3Check ended.rc:0 >Running:(3.3.8.1):C:\Program Files (x86)\AutoIt3\autoit3.exe "L:\TOOLs\Macro\ TEST\TEST ArrayUnique.au3" --> Press Ctrl+Alt+F5 to Restart or Ctrl+Break to Stop TEST OLD: 61.8902842999841 TEST NEW: 7.55799276374465 +>14:57:34 AutoIt3.exe ended.rc:0 >Exit code: 0 Time: 0.974
RESULTS AutoIt 3.3.9.25:
>"C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.exe" /run /beta /ErrorStdOut /in "L:\TOOLs\Macro\ TEST\TEST ArrayUnique.au3" /UserParams +>14:58:19 Starting AutoIt3Wrapper v.2.1.3.2 SciTE v.3.3.7.0 ; Keyboard:00000415 OS:WIN_7/Service Pack 1 CPU:X64 OS:X64 Environment(Language:0415 Keyboard:00000415 OS:WIN_7/Service Pack 1 CPU:X64 OS:X64) >Running AU3Check (3.3.9.25) from:C:\Program Files (x86)\AutoIt3\Beta +>14:58:19 AU3Check ended.rc:0 >Running:(3.3.9.25):C:\Program Files (x86)\AutoIt3\Beta\autoit3.exe "L:\TOOLs\Macro\ TEST\TEST ArrayUnique.au3" --> Press Ctrl+Alt+F5 to Restart or Ctrl+Break to Stop TEST OLD: 9.17964658320134 TEST NEW: 3.99375813207523 +>14:58:19 AutoIt3.exe ended.rc:0 >Exit code: 0 Time: 0.750
TEST SCRIPT:
#include <array.au3> Local $aTest[100][100] For $iRows = 0 To 99 For $iCols = 0 To 99 $aTest[$iRows][$iCols] = '$iRows = ' & $iRows & ' $iCols = ' & $iCols Next Next Local $start = TimerInit() _ArrayUnique($aTest) ConsoleWrite('TEST OLD: ' & TimerDiff($start) & @CRLF) Local $start = TimerInit() _ArrayUnique_NEW($aTest) ConsoleWrite('TEST NEW: ' & TimerDiff($start) & @CRLF) Func _ArrayUnique_NEW(Const ByRef $aArray, $iColumn = Default, $iBase = Default, $iCase = Default, $iFlags = Default) If $iColumn = Default Then $iColumn = 1 If $iBase = Default Then $iBase = 0 If $iCase = Default Then $iCase = 0 If $iFlags = Default Then $iFlags = 1 ; Start bounds checking Local $iUBound = UBound($aArray) If $iUBound = 0 Then Return SetError(1, 0, 0) ; Check if array is empty, or not an array ; $iBase can only be 0 or 1, if anything else, return with an error If $iBase < 0 Or $iBase > 1 Or (Not IsInt($iBase)) Then Return SetError(2, 0, 0) If $iCase < 0 Or $iCase > 1 Or (Not IsInt($iCase)) Then Return SetError(2, 0, 0) If $iFlags < 0 Or $iFlags > 1 Or (Not IsInt($iFlags)) Then Return SetError(4, 0, 0) Local $iDims = UBound($aArray, 0), $iNumColumns = UBound($aArray, 2) If $iDims > 2 Then Return SetError(3, 0, 0) ; checks the given dimension is valid If ($iColumn < 1) Or ($iNumColumns = 0 And ($iColumn - 1 > $iNumColumns)) Or ($iNumColumns > 0 And ($iColumn > $iNumColumns)) Then Return SetError(3, 0, 0) ; make $iColumn an array index, note this is ignored for 1D arrays $iColumn -= 1 ; create dictionary Local $oD = ObjCreate("Scripting.Dictionary") ; compare mode for strings ; 0 = binary, which is case sensitive ; 1 = text, which is case insensitive ; this expression forces either 1 or 0 $oD.CompareMode = Number(Not $iCase) Local $vElem ; walk the input array $iUBound -=1 For $i = $iBase To $iUBound If $iDims = 1 Then ; 1D array $vElem = $aArray[$i] Else ; 2D array $vElem = $aArray[$i][$iColumn] EndIf ; add key to dictionary ; NOTE: accessing the value (.Item property) of a key that doesn't exist creates the key :) ; keys are guaranteed to be unique $oD.Item($vElem) Next ; ; return the array of unique keys If BitAND($iFlags, 1) = 1 Then Local $aTemp = $oD.Keys() _ArrayInsert($aTemp, 0, $oD.Count) Return $aTemp Else Return $oD.Keys() EndIf EndFunc ;==>_ArrayUnique
comment:6 Changed 11 years ago by BrewManNH
Two things.
First thing, your 2 tests aren't equal because the second time you run it the array has already run through the _ArrayUnique function and isn't the same the second test.
Second thing, reverse the two tests and the results will be reversed with the new function being just as slow as the old function, slow being a relative term here.
#include <array.au3> Local $aTest[100][100], $aTest1 For $iRows = 0 To 99 For $iCols = 0 To 99 $aTest[$iRows][$iCols] = '$iRows = ' & $iRows & ' $iCols = ' & $iCols Next Next $aTest1 = $aTest ; make 2 identical arrays Local $start = TimerInit() _ArrayUnique_NEW($aTest1) ; swap the new one to run first ConsoleWrite('TEST NEW: ' & TimerDiff($start) & @CRLF) Local $start = TimerInit() _ArrayUnique($aTest) ; and original to run second ConsoleWrite('TEST OLD: ' & TimerDiff($start) & @CRLF) Func _ArrayUnique_NEW(Const ByRef $aArray, $iColumn = Default, $iBase = Default, $iCase = Default, $iFlags = Default) If $iColumn = Default Then $iColumn = 1 If $iBase = Default Then $iBase = 0 If $iCase = Default Then $iCase = 0 If $iFlags = Default Then $iFlags = 1 ; Start bounds checking Local $iUBound = UBound($aArray) If $iUBound = 0 Then Return SetError(1, 0, 0) ; Check if array is empty, or not an array ; $iBase can only be 0 or 1, if anything else, return with an error If $iBase < 0 Or $iBase > 1 Or (Not IsInt($iBase)) Then Return SetError(2, 0, 0) If $iCase < 0 Or $iCase > 1 Or (Not IsInt($iCase)) Then Return SetError(2, 0, 0) If $iFlags < 0 Or $iFlags > 1 Or (Not IsInt($iFlags)) Then Return SetError(4, 0, 0) Local $iDims = UBound($aArray, 0), $iNumColumns = UBound($aArray, 2) If $iDims > 2 Then Return SetError(3, 0, 0) ; checks the given dimension is valid If ($iColumn < 1) Or ($iNumColumns = 0 And ($iColumn - 1 > $iNumColumns)) Or ($iNumColumns > 0 And ($iColumn > $iNumColumns)) Then Return SetError(3, 0, 0) ; make $iColumn an array index, note this is ignored for 1D arrays $iColumn -= 1 ; create dictionary Local $oD = ObjCreate("Scripting.Dictionary") ; compare mode for strings ; 0 = binary, which is case sensitive ; 1 = text, which is case insensitive ; this expression forces either 1 or 0 $oD.CompareMode = Number(Not $iCase) Local $vElem ; walk the input array $iUBound -=1 For $i = $iBase To $iUBound If $iDims = 1 Then ; 1D array $vElem = $aArray[$i] Else ; 2D array $vElem = $aArray[$i][$iColumn] EndIf ; add key to dictionary ; NOTE: accessing the value (.Item property) of a key that doesn't exist creates the key :) ; keys are guaranteed to be unique $oD.Item($vElem) Next ; ; return the array of unique keys If BitAND($iFlags, 1) = 1 Then Local $aTemp = $oD.Keys() _ArrayInsert($aTemp, 0, $oD.Count) Return $aTemp Else Return $oD.Keys() EndIf EndFunc ;==>_ArrayUnique
Try this one and see what I'm talking about, reverse the 2 tests back and forth and you'll see that they run equally as fast.
comment:7 Changed 11 years ago by mlipok
I see what you mean
but see even my modified script:
#include <array.au3> Local $aTest[100][100], $aTest1 For $iRows = 0 To 99 For $iCols = 0 To 99 $aTest[$iRows][$iCols] = '$iRows = ' & $iRows & ' $iCols = ' & $iCols Next Next Local $aTest_OLD = $aTest ; make 2 identical arrays Local $aTest_NEW = $aTest ; make 3 identical arrays _ArrayUnique($aTest) ; Initial test Local $start = TimerInit() _ArrayUnique($aTest_OLD) ConsoleWrite('TEST OLD: ' & TimerDiff($start) & @CRLF) Local $start = TimerInit() _ArrayUnique_NEW($aTest_NEW) ; swap the new one to run first ConsoleWrite('TEST NEW: ' & TimerDiff($start) & @CRLF) Func _ArrayUnique_NEW(Const ByRef $aArray, $iColumn = Default, $iBase = Default, $iCase = Default, $iFlags = Default) If $iColumn = Default Then $iColumn = 1 If $iBase = Default Then $iBase = 0 If $iCase = Default Then $iCase = 0 If $iFlags = Default Then $iFlags = 1 ; Start bounds checking Local $iUBound = UBound($aArray) If $iUBound = 0 Then Return SetError(1, 0, 0) ; Check if array is empty, or not an array ; $iBase can only be 0 or 1, if anything else, return with an error If $iBase < 0 Or $iBase > 1 Or (Not IsInt($iBase)) Then Return SetError(2, 0, 0) If $iCase < 0 Or $iCase > 1 Or (Not IsInt($iCase)) Then Return SetError(2, 0, 0) If $iFlags < 0 Or $iFlags > 1 Or (Not IsInt($iFlags)) Then Return SetError(4, 0, 0) Local $iDims = UBound($aArray, 0), $iNumColumns = UBound($aArray, 2) If $iDims > 2 Then Return SetError(3, 0, 0) ; checks the given dimension is valid If ($iColumn < 1) Or ($iNumColumns = 0 And ($iColumn - 1 > $iNumColumns)) Or ($iNumColumns > 0 And ($iColumn > $iNumColumns)) Then Return SetError(3, 0, 0) ; make $iColumn an array index, note this is ignored for 1D arrays $iColumn -= 1 ; create dictionary Local $oD = ObjCreate("Scripting.Dictionary") ; compare mode for strings ; 0 = binary, which is case sensitive ; 1 = text, which is case insensitive ; this expression forces either 1 or 0 $oD.CompareMode = Number(Not $iCase) Local $vElem ; walk the input array $iUBound -=1 For $i = $iBase To $iUBound If $iDims = 1 Then ; 1D array $vElem = $aArray[$i] Else ; 2D array $vElem = $aArray[$i][$iColumn] EndIf ; add key to dictionary ; NOTE: accessing the value (.Item property) of a key that doesn't exist creates the key :) ; keys are guaranteed to be unique $oD.Item($vElem) Next ; ; return the array of unique keys If BitAND($iFlags, 1) = 1 Then Local $aTemp = $oD.Keys() _ArrayInsert($aTemp, 0, $oD.Count) Return $aTemp Else Return $oD.Keys() EndIf EndFunc ;==>_ArrayUnique
RESULTS AutoIt 3.3.8.1:
>"C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.exe" /run /prod /ErrorStdOut /in "L:\TOOLs\Macro\ TEST\TEST ArrayUnique2.au3" /UserParams +>18:41:28 Starting AutoIt3Wrapper v.2.1.3.2 SciTE v.3.3.7.0 ; Keyboard:00000415 OS:WIN_7/Service Pack 1 CPU:X64 OS:X64 Environment(Language:0415 Keyboard:00000415 OS:WIN_7/Service Pack 1 CPU:X64 OS:X64) >Running AU3Check (3.3.9.5) from:C:\Program Files (x86)\AutoIt3 +>18:41:28 AU3Check ended.rc:0 >Running:(3.3.8.1):C:\Program Files (x86)\AutoIt3\autoit3.exe "L:\TOOLs\Macro\ TEST\TEST ArrayUnique2.au3" --> Press Ctrl+Alt+F5 to Restart or Ctrl+Break to Stop TEST OLD: 62.1766151060786 TEST NEW: 7.80358215946651 +>18:41:28 AutoIt3.exe ended.rc:0 >Exit code: 0 Time: 1.169
RESULTS AutoIt 3.3.9.25:
>"C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.exe" /run /beta /ErrorStdOut /in "L:\TOOLs\Macro\ TEST\TEST ArrayUnique2.au3" /UserParams +>18:41:58 Starting AutoIt3Wrapper v.2.1.3.2 SciTE v.3.3.7.0 ; Keyboard:00000415 OS:WIN_7/Service Pack 1 CPU:X64 OS:X64 Environment(Language:0415 Keyboard:00000415 OS:WIN_7/Service Pack 1 CPU:X64 OS:X64) >Running AU3Check (3.3.9.25) from:C:\Program Files (x86)\AutoIt3\Beta +>18:41:58 AU3Check ended.rc:0 >Running:(3.3.9.25):C:\Program Files (x86)\AutoIt3\Beta\autoit3.exe "L:\TOOLs\Macro\ TEST\TEST ArrayUnique2.au3" --> Press Ctrl+Alt+F5 to Restart or Ctrl+Break to Stop TEST OLD: 3.76685532009558 TEST NEW: 3.74821554549098 +>18:41:58 AutoIt3.exe ended.rc:0 >Exit code: 0 Time: 0.962
and focus on:
_ArrayUnique($aTest) ; Initial test
now your statement:
"
Second thing, reverse the two tests and the results will be reversed with the new function being just as slow as the old function, slow being a relative term here.
"
is not applicable for this new script.
QUESTION: why initial _ArrayUnique is slower than each subsequent call.
comment:8 Changed 11 years ago by BrewManNH
You'll find that when doing speed comparisons on functions, you always have to try them in a different order each time or the results will make you see something that isn't real. This is an example of that, your 2 tests are identically written, yet the first one to run will always take a little bit longer than the second run of it.
Also, a difference of .02 ms is statistically insignificant because of the way AutoIt works.
Also, the comparison to 3.3.8.1 is invalid as that uses a very slow script that was replaced within the last few beta releases.
comment:9 Changed 11 years ago by Jos
- Resolution set to Rejected
- Status changed from new to closed
comment:10 Changed 11 years ago by mlipok
Thank you very much for your lecture.
For the future, I will try to first carry out appropriate tests.
Guidelines for posting comments:
- You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
- In-depth discussions should take place on the forum.
For more information see the full version of the ticket guidelines here.
sorry for short topic name
please change to
UDF - _ArrayUnique - proposal