Sign in to follow this  
Followers 0
Gibbo

_ArrayUnique Overhaul

8 posts in this topic

#1 ·  Posted (edited)

Recently I found myself needing to "Uniqueify" large arrays of data. Not happy with the speed I decided to check out how _ArrayUnique worked and if it could be improved.

Below is my overhauled version of _ArrayUnique.

"Uniqueify" An array of 500 random numbers (average of 5 results)

Old: 274.597787502462

New: 240.237994573652

"Uniqueify" An array of 1000 random numbers (average of 5 results)

Old: 1070.06629280595

New: 920.537746095923

Still not fast but faster

Changed ALL Dim's to Local's
From the help file:
  "You should use Local or Global, instead of Dim, to explicitly state which scope is desired for a variable/constant/array."
Changed:
  Dim $aArrayTmp[1] ;Declare blank array, which will hold the dimension declared by user
  For $i = 0 To $iUboundDim - 1
   _ArrayAdd($aArrayTmp, <itemtoadd> ) ;$iDimension-1 to match Dimension
  Next
  _ArrayDelete($aArrayTmp, 0) ;Get rid of 1st-element which is blank
To:
  Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
  For $i = 0 To $iUboundDim - 1 ;Loop through "Rows"
   $aArrayTmp[$i] = <itemtoadd> ;$iDimension-1 to match Dimension
  Next
It is silly to declare a "blank" array (and delete the first "empty value")if you already know it's intended dimentions
This also removed the need for _ArrayAdd (No more ReDim's YAY!)

Changed If,Then, Else statements to Switch statements where appropriate for ease of reading (they are supposed to be faster too)

Trimmed:
  If Not $iDimension > 0 Then
   Return SetError(3, 0, 0) ;Check to see if it is valid array dimension, Should be greater than 0
  Else
To:
  If $iDimension < 1 Then Return SetError(3, 0, 0) ;Check to see if it is valid array dimension, Should be greater than 0

Changed:
  $aArrayTmp = StringSplit(StringTrimRight($sHold, StringLen($vDelim)), $vDelim, 1) ;Split the string into an array
  Return $aArrayTmp ;SmOke_N's version used to Return SetError(0, 0, 0)

To:
  $sHold = StringTrimRight($sHold, StringLen($vDelim))
  $aArrayTmp = StringSplit($sHold, $vDelim, 1) ;Split the string into an array
  Return $aArrayTmp ;SmOke_N's version used to Return SetError(0, 0, 0)
For clarity

; #FUNCTION# ====================================================================================================================
; Name...........: _ArrayUnique
; Description ...: Returns the Unique Elements of a 1-dimensional array.
; Syntax.........: _ArrayUnique($aArray[, $iDimension = 1[, $iBase = 0[, $iCase = 0[, $vDelim = "|"]]]])
; Parameters ....: $aArray - The Array to use
;                 $iDimension  - [optional] The Dimension of the Array to use
;                 $iBase  - [optional] Is the Array 0-base or 1-base index.  0-base by default
;                 $iCase  - [optional] Flag to indicate if the operations should be case sensitive.
;                 0 = not case sensitive, using the user's locale (default)
;                 1 = case sensitive
;                 2 = not case sensitive, using a basic/faster comparison
;                 $vDelim  - [optional] One or more characters to use as delimiters.  However, cannot forsee its usefullness
; Return values .: Success - Returns a 1-dimensional array containing only the unique elements of that Dimension
;                 Failure - Returns 0 and Sets @Error:
;                 0 - No error.
;                 1 - Returns 0 if parameter is not an array.
;                 2 - _ArrayUnique failed for some other reason
;                 3 - Array dimension is invalid, should be an integer greater than 0
; Author ........: SmOke_N
; Modified.......: litlmike, Gibbo
; Remarks .......: Returns an array, the first element ($array[0]) contains the number of strings returned, the remaining elements ($array[1], $array[2], etc.) contain the unique strings.
; Related .......: _ArrayMax, _ArrayMin
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _ArrayUnique($aArray, $iDimension = 1, $iBase = 0, $iCase = 0, $vDelim = "|")
    Local $iUboundDim
    ;$aArray used to be ByRef, but litlmike altered it to allow for the choosing of 1 Array Dimension, without altering the original array
    If $vDelim = "|" Then $vDelim = Chr(01) ; by SmOke_N, modified by litlmike
    If Not IsArray($aArray) Then Return SetError(1, 0, 0) ;Check to see if it is valid array

    ;Checks that the given Dimension is Valid
    If $iDimension < 1 Then Return SetError(3, 0, 0) ;Check to see if it is valid array dimension, Should be greater than 0
    ;If Dimension Exists, then get the number of "Rows"
    $iUboundDim = UBound($aArray, 1) ;Get Number of "Rows"
    If @error Then Return SetError(3, 0, 0) ;2 = Array dimension is invalid.

    ;If $iDimension Exists, And the number of "Rows" is Valid:
    Switch $iDimension = 1
        Case False ;Makes sure the Array dimension desired is more than 1-dimensional
            Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
            For $i = 0 To $iUboundDim - 1 ;Loop through "Rows"
                $aArrayTmp[$i] = $aArray[$i][$iDimension - 1] ;$iDimension-1 to match Dimension
            Next
        Case Else ;Makes sure the Array dimension desired is 1-dimensional
            ;If Dimension Exists, And the number of "Rows" is Valid, and the Dimension desired is not > 1, then:
            ;For the Case that the array is 1-Dimensional
            Switch UBound($aArray, 0)
                Case 1 ;Makes sure the Array is only 1-Dimensional
                    Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
                    For $i = 0 To $iUboundDim - 1
                        $aArrayTmp[$i] = $aArray[$i]
                    Next
                Case Else ;For the Case that the array is 2-Dimensional
                    Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
                    For $i = 0 To $iUboundDim - 1
                        $aArrayTmp[$i] = $aArray[$i][$iDimension - 1] ;$iDimension-1 to match Dimension
                    Next
            EndSwitch
    EndSwitch

    Local $sHold ;String that holds the Unique array info
    For $iCC = $iBase To $iUboundDim - 1 ;Loop Through array
        ;If Not the case that the element is already in $sHold, then add it
        Switch StringInStr($vDelim & $sHold, $vDelim & $aArrayTmp[$iCC] & $vDelim, $iCase)
            Case False
                $sHold &= $aArrayTmp[$iCC] & $vDelim
        EndSwitch
    Next
    If $sHold Then
        $sHold = StringTrimRight($sHold, StringLen($vDelim))
        $aArrayTmp = StringSplit($sHold, $vDelim, 1) ;Split the string into an array
        Return $aArrayTmp ;SmOke_N's version used to Return SetError(0, 0, 0)
    EndIf
    Return SetError(2, 0, 0) ;If the script gets this far, it has failed
EndFunc   ;==>_ArrayUnique
Edited by Gibbo

Share this post


Link to post
Share on other sites



You're not checking for any array greater than a 2D array, if this is passed a 3D+ array it will crash.


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

Share this post


Link to post
Share on other sites

@BrewManNH

Does that mean the built in function doesnt check either? ;)

I have fixed this it now checks if the array is greater than two dimentions.

Changed:

Local $sHold ;String that holds the Unique array info
    For $iCC = $iBase To $iUboundDim - 1 ;Loop Through array
        ;If Not the case that the element is already in $sHold, then add it
        Switch StringInStr($vDelim & $sHold, $vDelim & $aArrayTmp[$iCC] & $vDelim, $iCase)
            Case False
                $sHold &= $aArrayTmp[$iCC] & $vDelim
        EndSwitch
    Next

To: :D

Local $sHold ;String that holds the Unique array info
For $iCC = $iBase To $iUboundDim - 1 ;Loop Through array
  ;If Not the case that the element is already in $sHold, then add it
  Switch IsDeclared($aArrayTmp[$iCC] & '$')
   Case False
    Assign($aArrayTmp[$iCC] & '$', 0, 1)
    $sHold &= $aArrayTmp[$iCC] & $vDelim
  EndSwitch
Next

Now it is insanely fast!

"Uniqueify" An array of 500 random numbers (average of 5 results)

4.97969129224458

"Uniqueify" An array of 1000 random numbers (average of 5 results)

10.0195612857199

:)

; #FUNCTION# ====================================================================================================================
; Name...........: _ArrayUnique
; Description ...: Returns the Unique Elements of a 1-dimensional array.
; Syntax.........: _ArrayUnique($aArray[, $iDimension = 1[, $iBase = 0[, $iCase = 0[, $vDelim = "|"]]]])
; Parameters ....: $aArray - The Array to use
;                 $iDimension  - [optional] The Dimension of the Array to use
;                 $iBase  - [optional] Is the Array 0-base or 1-base index.  0-base by default
;                 $iCase  - [optional] Flag to indicate if the operations should be case sensitive.
;                 0 = not case sensitive, using the user's locale (default)
;                 1 = case sensitive
;                 2 = not case sensitive, using a basic/faster comparison
;                 $vDelim  - [optional] One or more characters to use as delimiters.  However, cannot forsee its usefullness
; Return values .: Success - Returns a 1-dimensional array containing only the unique elements of that Dimension
;                 Failure - Returns 0 and Sets @Error:
;                 0 - No error.
;                 1 - Returns 0 if parameter is not an array.
;                 2 - _ArrayUnique failed for some other reason
;                 3 - Array dimension is invalid, should be an integer greater than 0
;                 4 - Array has more than two dimensions
; Author ........: SmOke_N
; Modified.......: litlmike, Gibbo
; Remarks .......: Returns an array, the first element ($array[0]) contains the number of strings returned, the remaining elements ($array[1], $array[2], etc.) contain the unique strings.
; Related .......: _ArrayMax, _ArrayMin
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _ArrayUnique($aArray, $iDimension = 1, $iBase = 0, $iCase = 0, $vDelim = "|")
Local $iUboundDim
;$aArray used to be ByRef, but litlmike altered it to allow for the choosing of 1 Array Dimension, without altering the original array
If Not IsArray($aArray) Then Return SetError(1, 0, 0) ;Check to see if it is valid array
If UBound($aArray, 0) > 2 Then Return SetError(4, 0, 0) ;Check to see if the array has more than two dimentions
If $vDelim = "|" Then $vDelim = Chr(01) ; by SmOke_N, modified by litlmike
;Checks that the given Dimension is Valid
If $iDimension < 1 Then Return SetError(3, 0, 0) ;Check to see if it is valid array dimension, Should be greater than 0
;If Dimension Exists, then get the number of "Rows"
$iUboundDim = UBound($aArray, 1) ;Get Number of "Rows"
If @error Then Return SetError(3, 0, 0) ;2 = Array dimension is invalid.
;If $iDimension Exists, And the number of "Rows" is Valid:
Switch $iDimension = 1
  Case False ;Makes sure the Array dimension desired is more than 1-dimensional
   Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
   For $i = 0 To $iUboundDim - 1 ;Loop through "Rows"
    $aArrayTmp[$i] = $aArray[$i][$iDimension - 1] ;$iDimension-1 to match Dimension
   Next
  Case Else ;Makes sure the Array dimension desired is 1-dimensional
   ;If Dimension Exists, And the number of "Rows" is Valid, and the Dimension desired is not > 1, then:
   ;For the Case that the array is 1-Dimensional
   Switch UBound($aArray, 0)
    Case 1 ;Makes sure the Array is only 1-Dimensional
     Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
     For $i = 0 To $iUboundDim - 1
      $aArrayTmp[$i] = $aArray[$i]
     Next
    Case Else ;For the Case that the array is 2-Dimensional
     Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
     For $i = 0 To $iUboundDim - 1
      $aArrayTmp[$i] = $aArray[$i][$iDimension - 1] ;$iDimension-1 to match Dimension
     Next
   EndSwitch
EndSwitch
Local $sHold ;String that holds the Unique array info
For $iCC = $iBase To $iUboundDim - 1 ;Loop Through array
  ;If Not the case that the element is already in $sHold, then add it
  Switch IsDeclared($aArrayTmp[$iCC] & '$')
   Case False
    Assign($aArrayTmp[$iCC] & '$', 0, 1)
    $sHold &= $aArrayTmp[$iCC] & $vDelim
  EndSwitch
Next
If $sHold Then
  $sHold = StringTrimRight($sHold, StringLen($vDelim))
  $aArrayTmp = StringSplit($sHold, $vDelim, 1) ;Split the string into an array
  Return $aArrayTmp ;SmOke_N's version used to Return SetError(0, 0, 0)
EndIf
Return SetError(2, 0, 0) ;If the script gets this far, it has failed
EndFunc   ;==>_ArrayUnique

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Found another issue with error checking.

Requests for a column greater than ubound($aArray,2) would cause a crash

I rewrote all the error checking to make sure it caches everything.

On a side note using the term "Dimentions" to describe different things is just plain confusing. Also "dimentions" should realy start at "0" for consistancy. (alltthough that would break existing scripts)

EDIT: Script indenting failure

EDIT2: needed "$iDimension-1" not "$iDimension" in one of the error checks (SEE Confusing!)

; #FUNCTION# ====================================================================================================================
; Name...........: _ArrayUnique
; Description ...: Returns the Unique Elements of a 1-dimensional array.
; Syntax.........: _ArrayUnique($aArray[, $iDimension = 1[, $iBase = 0[, $iCase = 0[, $vDelim = "|"]]]])
; Parameters ....: $aArray - The Array to use
;                 $iDimension  - [optional] The Dimension of the Array to use
;                 $iBase  - [optional] Is the Array 0-base or 1-base index.  0-base by default
;                 $iCase  - [optional] Flag to indicate if the operations should be case sensitive.
;                 0 = not case sensitive, using the user's locale (default)
;                 1 = case sensitive
;                 2 = not case sensitive, using a basic/faster comparison
;                 $vDelim  - [optional] One or more characters to use as delimiters.  However, cannot forsee its usefullness
; Return values .: Success - Returns a 1-dimensional array containing only the unique elements of that Dimension
;                 Failure - Returns 0 and Sets @Error:
;                 0 - No error.
;                 1 - Returns 0 if parameter is not an array.
;                 2 - _ArrayUnique failed for some other reason
;                 3 - Array dimension is invalid, should be an integer greater than 0
;                 4 - Array has more than two dimensions
; Author ........: SmOke_N
; Modified.......: litlmike, Gibbo
; Remarks .......: Returns an array, the first element ($array[0]) contains the number of strings returned, the remaining elements ($array[1], $array[2], etc.) contain the unique strings.
; Related .......: _ArrayMax, _ArrayMin
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _ArrayUnique($aArray, $iDimension = 1, $iBase = 0, $iCase = 0, $vDelim = "|")
    ;$aArray used to be ByRef, but litlmike altered it to allow for the choosing of 1 Array Dimension, without altering the original array
    If Not IsArray($aArray) Then Return SetError(1, 0, 0) ;Check to see if it is valid array
    If UBound($aArray, 0) > 2 Then Return SetError(4, 0, 0) ;Check to see if the array has more than two dimentions

    ;Check the given Dimension is Valid
    If $iDimension < 1 Then Return SetError(3, 0, 0) ;Check to see if dimension is greater than 0
    If $iDimension - 1 > UBound($aArray, 2) Then Return SetError(3, 0, 0) ;Array dimension is invalid.

    ;Get the number of "Rows"
    Local $iUboundDim = UBound($aArray, 1) ;Get Number of "Rows"

    ;If $iDimension Exists, And the number of "Rows" is Valid:
    Switch $iDimension = 1
        Case False ;Makes sure the Array dimension desired is more than 1-dimensional
            Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
            For $i = 0 To $iUboundDim - 1 ;Loop through "Rows"
                $aArrayTmp[$i] = $aArray[$i][$iDimension - 1] ;$iDimension-1 to match Dimension
            Next
        Case Else ;Makes sure the Array dimension desired is 1-dimensional
            ;If Dimension Exists, And the number of "Rows" is Valid, and the Dimension desired is not > 1, then:
            ;For the Case that the array is 1-Dimensional
            Switch UBound($aArray, 0)
                Case 1 ;Makes sure the Array is only 1-Dimensional
                    Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
                    For $i = 0 To $iUboundDim - 1
                        $aArrayTmp[$i] = $aArray[$i]
                    Next
                Case Else ;For the Case that the array is 2-Dimensional
                    Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
                    For $i = 0 To $iUboundDim - 1
                        $aArrayTmp[$i] = $aArray[$i][$iDimension - 1] ;$iDimension-1 to match Dimension
                    Next
            EndSwitch
    EndSwitch

    If $vDelim = "|" Then $vDelim = Chr(01) ; by SmOke_N, modified by litlmike
    Local $sHold ;String that holds the Unique array info
    For $iCC = $iBase To $iUboundDim - 1 ;Loop Through array
        ;If Not the case that the element is already in $sHold, then add it
        Switch IsDeclared($aArrayTmp[$iCC] & '$')
            Case False
                Assign($aArrayTmp[$iCC] & '$', 0, 1)
                $sHold &= $aArrayTmp[$iCC] & $vDelim
        EndSwitch
    Next

    If $sHold Then
        $sHold = StringTrimRight($sHold, StringLen($vDelim))
        $aArrayTmp = StringSplit($sHold, $vDelim, 1) ;Split the string into an array
        Return $aArrayTmp ;SmOke_N's version used to Return SetError(0, 0, 0)
    EndIf
    Return SetError(2, 0, 0) ;If the script gets this far, it has failed
EndFunc   ;==>_ArrayUnique
Edited by Gibbo

Share this post


Link to post
Share on other sites

This wheel has been reinvented several times already. Here's a post I started with an idea I had. There's some good discussion in there and the solutions are much faster than even yours. My final version is in the first post.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

@wraithdu

I had a look at your version before. It is fast but doesn't scale well for some reason.

From your example: ($z = 500000, average of 5 runs each)

Yours:

5.53712680343056

Mine:

2.93016771711739

Mine also doesnt rely on ObjCreate("Scripting.Dictionary").

EDIT:

While trying some text (574896 items):

$sFile= "C:\Windows\WindowsUpdate.log"
$a=FileRead($sFile)
$a=StringSplit($a,@TAB&@CRLF,2)
_ArrayConcatenate($a,$a)
_ArrayConcatenate($a,$a)
_ArrayConcatenate($a,$a)
ConsoleWrite(UBound($a)&@CRLF)

I found that the version using ObjCreate("Scripting.Dictionary") drops entries:

[117]|16:41:03:792
[118]|16:41:04:297
[119]|16:41:04:299
[120]|16:41:04:311
[121]|132c
[122]|>>##  RESUMED  ## AU: Search for updates [CallId = {3EE45878-1C5F-45EC-9E1D-63F33F952797}]
[123]|16:41:04:312

Should be:

[117]|16:41:03:792
[118]|16:41:04:297
[119]|16:41:04:299
[120]|**  END  **  Agent: Finding updates [CallerId = AutomaticUpdates]
[121]|16:41:04:311
[122]|132c
[123]|>>##  RESUMED  ## AU: Search for updates [CallId = {3EE45878-1C5F-45EC-9E1D-63F33F952797}]
[124]|16:41:04:312

Not sure if it is just the ones beginning with a * or not.

Edited by Gibbo

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

I used the method above to get the text from WindowsUpdate.log (574896 items) and used it to test an idea I had for matching with case sensitivity:

Switch IsDeclared($aArrayTmp[$iCC] & '$')
    Case False
        Assign($aArrayTmp[$iCC] & '$', $aArrayTmp[$iCC], 1) ;Store the correct case item in the case insensitive variable named the same
        $sHold &= $aArrayTmp[$iCC] & $vDelim
    Case True And $iCase = 1 ;Only bother checking variable contents if case is important (otherwise its existance is enough)
        Switch StringInStr($vDelim & Eval($aArrayTmp[$iCC] & '$'), $vDelim & $aArrayTmp[$iCC] & $vDelim, 1) ;instead of checking a possibly massive $sHold just check the case insensitive variable of the same name
            Case 0
                Assign($aArrayTmp[$iCC] & '$', Eval($aArrayTmp[$iCC] & '$') & $aArrayTmp[$iCC] & $vDelim, 1)
                $sHold &= $aArrayTmp[$iCC] & $vDelim
        EndSwitch
EndSwitch

Case insensitive:

1.82747950851224

Case sensitive:

4.11968048933211

three times slower but still quite fast for ~570000 items.

; #FUNCTION# ====================================================================================================================
; Name...........: _ArrayUnique
; Description ...: Returns the Unique Elements of a 1-dimensional array.
; Syntax.........: _ArrayUnique($aArray[, $iDimension = 1[, $iBase = 0[, $iCase = 0[, $vDelim = "|"]]]])
; Parameters ....: $aArray - The Array to use
;                 $iDimension  - [optional] The Dimension of the Array to use
;                 $iBase  - [optional] Is the Array 0-base or 1-base index.  0-base by default
;                 $iCase  - [optional] Flag to indicate if the operations should be case sensitive.
;                 0 = not case sensitive, using the user's locale (default)
;                 1 = case sensitive
;                 2 = not case sensitive, using a basic/faster comparison
;                 $vDelim  - [optional] One or more characters to use as delimiters.  However, cannot forsee its usefullness
; Return values .: Success - Returns a 1-dimensional array containing only the unique elements of that Dimension
;                 Failure - Returns 0 and Sets @Error:
;                 0 - No error.
;                 1 - Returns 0 if parameter is not an array.
;                 2 - _ArrayUnique failed for some other reason
;                 3 - Array dimension is invalid, should be an integer greater than 0
;                 4 - Array has more than two dimensions
; Author ........: SmOke_N
; Modified.......: litlmike, Gibbo
; Remarks .......: Returns an array, the first element ($array[0]) contains the number of strings returned, the remaining elements ($array[1], $array[2], etc.) contain the unique strings.
; Related .......: _ArrayMax, _ArrayMin
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _ArrayUnique($aArray, $iDimension = 1, $iBase = 0, $iCase = 0, $vDelim = "|")
    ;$aArray used to be ByRef, but litlmike altered it to allow for the choosing of 1 Array Dimension, without altering the original array
    If Not IsArray($aArray) Then Return SetError(1, 0, 0) ;Check to see if it is valid array
    If UBound($aArray, 0) > 2 Then Return SetError(4, 0, 0) ;Check to see if the array has more than two dimentions

    ;Check the given Dimension is Valid
    If $iDimension < 1 Then Return SetError(3, 0, 0) ;Check to see if dimension is greater than 0
    If $iDimension - 1 > UBound($aArray, 2) Then Return SetError(3, 0, 0) ;Array dimension is invalid.

    ;Get the number of "Rows"
    Local $iUboundDim = UBound($aArray, 1) ;Get Number of "Rows"

    ;If $iDimension Exists, And the number of "Rows" is Valid:
    Switch $iDimension = 1
        Case False ;Makes sure the Array dimension desired is more than 1-dimensional
            Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
            For $i = 0 To $iUboundDim - 1 ;Loop through "Rows"
                $aArrayTmp[$i] = $aArray[$i][$iDimension - 1] ;$iDimension-1 to match Dimension
            Next
        Case Else ;Makes sure the Array dimension desired is 1-dimensional
            ;If Dimension Exists, And the number of "Rows" is Valid, and the Dimension desired is not > 1, then:
            ;For the Case that the array is 1-Dimensional
            Switch UBound($aArray, 0)
                Case 1 ;Makes sure the Array is only 1-Dimensional
                    Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
                    For $i = 0 To $iUboundDim - 1
                        $aArrayTmp[$i] = $aArray[$i]
                    Next
                Case Else ;For the Case that the array is 2-Dimensional
                    Local $aArrayTmp[$iUboundDim] ;Declare array, which will hold the dimension declared by user
                    For $i = 0 To $iUboundDim - 1
                        $aArrayTmp[$i] = $aArray[$i][$iDimension - 1] ;$iDimension-1 to match Dimension
                    Next
            EndSwitch
    EndSwitch

    If $vDelim = "|" Then $vDelim = Chr(01) ; by SmOke_N, modified by litlmike

    Local $sHold ;String that holds the Unique array info
    For $iCC = $iBase To $iUboundDim - 1 ;Loop Through array
        ;If Not the case that the element is already in $sHold, then add it
        Switch IsDeclared($aArrayTmp[$iCC] & '$')
            Case False
                Assign($aArrayTmp[$iCC] & '$', $aArrayTmp[$iCC] & $vDelim, 1) ;Store the correct case item (and delimiter) in the case insensitive variable named the same
                $sHold &= $aArrayTmp[$iCC] & $vDelim
            Case True And $iCase = 1 ;Only bother checking variable contents if case is important (otherwise its existance is enough)
                Switch StringInStr($vDelim & Eval($aArrayTmp[$iCC] & '$'), $vDelim & $aArrayTmp[$iCC] & $vDelim, 1) ;instead of checking a possibly massive $sHold just check the case insensitive variable of the same name
                    Case 0
                        Assign($aArrayTmp[$iCC] & '$', Eval($aArrayTmp[$iCC] & '$') & $aArrayTmp[$iCC] & $vDelim, 1)
                        $sHold &= $aArrayTmp[$iCC] & $vDelim
                EndSwitch
        EndSwitch
    Next

    If $sHold Then
        $sHold = StringTrimRight($sHold, StringLen($vDelim))
        $aArrayTmp = StringSplit($sHold, $vDelim, 1) ;Split the string into an array
        Return $aArrayTmp ;SmOke_N's version used to Return SetError(0, 0, 0)
    EndIf
    Return SetError(2, 0, 0) ;If the script gets this far, it has failed
EndFunc   ;==>_ArrayUnique

EDIT: Forgot to add the dilimeter when the variable is first stored

Switch IsDeclared($aArrayTmp[$iCC] & '$')
   Case False
      Assign($aArrayTmp[$iCC] & '$', $aArrayTmp[$iCC], 1) ;Store the correct case item in the case insensitive variable named the same
      $sHold &= $aArrayTmp[$iCC] & $vDelim

Should have been:

Switch IsDeclared($aArrayTmp[$iCC] & '$')
   Case False
      Assign($aArrayTmp[$iCC] & '$', $aArrayTmp[$iCC] & $vDelim, 1) ;Store the correct case item (and delimiter) in the case insensitive variable named the same
      $sHold &= $aArrayTmp[$iCC] & $vDelim
Edited by Gibbo

Share this post


Link to post
Share on other sites

The last I'll mention on the subject... I see you switched to the Assign() method. There's some discussion in the thread I linked why I don't like that method, even though it is the fastest. To each his own, as long as it suits your purpose.

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

  • Similar Content

    • Triblade
      By Triblade
      Hi all,
       
      I was pondering over a question with regards to the speeds of reading something and did not see this kind of question in a forum search.
      The question: What is (technically) faster? Multiple reads from the same 3d array cell, or only once make a 'temp' variable from that cell and read the value from this? I don't know if either has any real impact at all anyway, but just wanted to ask anyway. :-)
       
      There may be a difference if the value holds an integer or a string (or something else) but in my case, is a simple integer.
      To hopefully clarify with a small bit of code:
      $process = $start - 15 If $xy[$process][3] <> "x" Then If _ArraySearch($open, $process, 1, $open[0][0], 0, 0, 1, 1) <> -1 Then UpdateOpen($xy[$process][5], $closed[0][0]) ElseIf $start > 0 And _ArraySearch($closed, $process, 1, $closed[0][0], 0, 0, 1, 0) = -1 Then Add_open($start, $closed[0][0], $counter, $process) EndIf EndIf You can read from this, that the array $closed[0][0] is being read 3 times. And this goes on further in the code I did not show.
      My question boils down to this, should I make a 'temp' variable to hold that $closed[0][0] value until the function is done?
       
      It may not have a real impact on my small script, but I really am interested in the answer at least.
       
      Regards,
      Tri.
    • dejhost
      By dejhost
      Hello ,
      Here are three stepts that I would like to speed up - if possible: 
      STEP 1: I am generating an array, containing binary numbers  up to a certain amount of digits. My script adds leading zeros, so that each number has equal amount of digits.
      Example: 14 digit Binary array:
      I am using the code
      For $i = 0 to 2^$bit-1 ; $bit amount of digits. for example: 14 $binary = ( Dec2Bin($i) ) ; Check length of binary string $adig = $bit - StringLen($binary) ; Determine how many leading 0 have to be added $zeros = "" For $j = 1 To $adig ; add leading "0"s $zeros = $zeros & "0" Next $BinArray[$i] = $zeros & $binary ;Write binary-number to file, leading "0" Next Func Dec2Bin($D) Return (BitShift($D, 1) ? Dec2Bin(BitShift($D, 1)) : "") & BitAnd($D, 1) EndFunc ;==> Dec2Bin() AutoIt v3.3.12.0   to generate the binary number. 
      STEP 2: I reduce the array to unique values. In my application, the binary-numbers do not have a start-bit or end-bit. This means, that
        are actually the same numbers, and only one of them is to remain in the array. All alterations aren't unique and shall be removed. Here is my code:
      For $i = 0 to Ubound($BinArray)-1 ; shift through all rows For $j = 1 to $bit ; shift through all the bits If $i = Ubound($BinArray) Then ; exit before exceeding the arrays boundries ExitLoop 2 EndIf $BinArray[$i] = StringRight ( $BinArray[$i], 1 ) & StringLeft ( $BinArray[$i], $bit-1 ) $BinArray = _ArrayUnique($BinArray, 0, 0, 0, 0, $ARRAYUNIQUE_AUTO) If @error <> 0 Then Msgbox(0, "Error in _ArrayUnique", "The Error Code is " & @error & " Abort.") Exit EndIf Next Next STEP 3: Finally, I write the remaining array into a text-file.
      For $i = 0 to Ubound($BinArray)-1 FileWrite($hFileOpen, $i & @TAB & $BinArray[$i] & @CRLF) Next  
      So my question is: any idea how to speed up this procedure? There certainly is a way to do this smarter. Btw.: Step 2 is optional.
      Thanks for helping,
      dejhost 
    • Grosminet
      By Grosminet
      Searching inside the forum, I don't succeed to get any explanation about a strange (for me !) phenomena:
      Using AutoIt, I have coded a "cortex of neurons Simulator" for which I handle several neurons activity (Action Potential and Postsynaptic Potential) which take a long time, about 20 ms per neuron to be processed. This is why I need a global loop running about 1s for a global cortex of 50 neurons.
      But when I move the mouse (in any direction, like rotating above the GUI) the speed of the loop increase significantly : around x8 times more ... !
      This happens only if the GUI has the focus. I did a check with the "Windows Task Manager" where I can see the CPU usage changing every time the mouse is moving (growing from 3% to 15%).
      I believe to remember some lecture about the influence of the user events regarding the "Application" capability to anticipate user actions by changing it's rate of pooling events, but I'm not sure it was in an AutoIt forum, or maybe it was in an other "developer forum" (like "Code Project", "Stackoverflow" , or ...?
      Could somebody help me to understand this behaviour ?
      If possible, is there a programmatic method to manage the speed of a simple "For, Next" loop ? I try to change the Application priority (setting to level 4 with "ProcessSetPriority"), but this seems not very efficient ....
      Thanks, Alain.

      FYI: I'm using :
      Autoit 3.3.14.2 Windows 7 Home Premium Service Pack 1 Computer ASUS N56V Screen resolution: 1920x1080 (recommended) Theme :Windows Classic
    • DrAhmed
      By DrAhmed
      Hey 
      I've these two functions to do a base64 conversation , Is there any way to compare the exact speed of both of them ?
      Func _Base64Encode($input) $input = Binary($input) Local $struct = DllStructCreate("byte[" & BinaryLen($input) & "]") DllStructSetData($struct, 1, $input) Local $strc = DllStructCreate("int") Local $a_Call = DllCall("Crypt32.dll", "int", "CryptBinaryToString", _ "ptr", DllStructGetPtr($struct), _ "int", DllStructGetSize($struct), _ "int", 1, _ "ptr", 0, _ "ptr", DllStructGetPtr($strc)) If @error Or Not $a_Call[0] Then Return SetError(1, 0, "") ; error calculating the length of the buffer needed EndIf Local $a = DllStructCreate("char[" & DllStructGetData($strc, 1) & "]") $a_Call = DllCall("Crypt32.dll", "int", "CryptBinaryToString", _ "ptr", DllStructGetPtr($struct), _ "int", DllStructGetSize($struct), _ "int", 1, _ "ptr", DllStructGetPtr($a), _ "ptr", DllStructGetPtr($strc)) If @error Or Not $a_Call[0] Then Return SetError(2, 0, ""); error encoding EndIf Return DllStructGetData($a, 1) EndFunc ;==>_Base64Encode  
      Func _Base64Encode($sData) Local $oXml = ObjCreate("Msxml2.DOMDocument") If Not IsObj($oXml) Then SetError(1, 1, 0) EndIf Local $oElement = $oXml.createElement("b64") If Not IsObj($oElement) Then SetError(2, 2, 0) EndIf $oElement.dataType = "bin.base64" $oElement.nodeTypedValue = Binary($sData) Local $sReturn = $oElement.Text If StringLen($sReturn) = 0 Then SetError(3, 3, 0) EndIf Return $sReturn EndFunc ;==>_Base64Encode  
    • The_Key_Maker
      By The_Key_Maker
      Hi guys, 
      I wonder if there is a speed meter gauge in AutoIT - did someone managed to create one without the need of excel, only using the AutoIT graphics?
      There is a great example (attached) from @GreenCan here in the excel's related gauge, but I can't use excel since it's not installed on the machine I need to run the AutoIT exe script on.
       
      Thanks!