Jump to content
Jfish

Possible _ArrayUnique bug?

Recommended Posts

One more quick data point, I re-ran my test with $iIntType at the default of 0 - but before I called _ArrayUnique I cast all values in the array to strings and it worked whereas before it failed.

@Jos edit crossed with my post ...

Edited by Jfish

Share this post


Link to post
Share on other sites

There is one other issue with _ArrayUnique: 

This line is not retrieving the correct cell when using _ArrayUnique($sourceArray,1)

Local $vFirstElem = ( ($iDims = 1) ? ($aArray[$iBase]) : ($aArray[$iColumn][$iBase]) )

and think it needs to be changed to:

Local $vFirstElem = ( ($iDims = 1) ? ($aArray[$iBase]) : ($aArray[$iBase][$iColumn]) )

To make the test for the first cell work properly.

Jos

Edited by Jos

Share this post


Link to post
Share on other sites

Jos,

Good spot with the base/column switch - my fault.

I seem to remember a discussion some time ago about IsInt returning True when used on doubles that held integer values - so I agree that we should use VarGetType to detect when a true integer is used:

; Autocheck of first element
If $iIntType = $ARRAYUNIQUE_AUTO Then
    Local $vFirstElem = ( ($iDims = 1) ? ($aArray[$iBase]) : ($aArray[$iBase][$iColumn]) )
    If StringRegExp(VarGetType($vFirstElem), "Int(32|64)") Then
        Switch VarGetType($vFirstElem)
            Case "Int32"
                $iIntType = $ARRAYUNIQUE_FORCE32
            Case "Int64"
                $iIntType = $ARRAYUNIQUE_FORCE64
        EndSwitch

    Else
        $iIntType = $ARRAYUNIQUE_FORCE32
    EndIf
EndIf

Now doubles fall through and we save a couple of lines on your suggested solution above.

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see 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

You can get rid of the RegExp.
 

; Autocheck of first element
If $iIntType = $ARRAYUNIQUE_AUTO Then
    Local $vFirstElem = ( ($iDims = 1) ? $aArray[$iBase] : $aArray[$iBase][$iColumn] )
    If StringInStr(VarGetType($vFirstElem), "Int") Then
        Switch VarGetType($vFirstElem)
            Case "Int32"
                $iIntType = $ARRAYUNIQUE_FORCE32
            Case "Int64"
                $iIntType = $ARRAYUNIQUE_FORCE64
        EndSwitch

    Else
        $iIntType = $ARRAYUNIQUE_FORCE32
    EndIf
EndIf

Edit: and perhaps a couple of parentheses.

Edited by czardas

Share this post


Link to post
Share on other sites

I stumbled upon this bug too:

The reproducer script is only 5 lines :P


A cross-platform implementation of the AutoIt language

My contributions to the AutoIt Community ##AutoIt at freenode, real-time chat

3fHNZJ.gif

Spoiler

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) intend to do that to anybody.

Share this post


Link to post
Share on other sites

I polished @czardas's snippet further:

If $iIntType = $ARRAYUNIQUE_AUTO Then
    Local $vFirstElem = ( ($iDims = 1) ? $aArray[$iBase] : $aArray[$iBase][$iColumn] )
    Switch VarGetType($vFirstElem)
        Case "Int32"
            $iIntType = $ARRAYUNIQUE_FORCE32
        Case "Int64"
            $iIntType = $ARRAYUNIQUE_FORCE64
        Case Else
            $iIntType = $ARRAYUNIQUE_FORCE32
    EndSwitch

Hope its not buggy >_<


A cross-platform implementation of the AutoIt language

My contributions to the AutoIt Community ##AutoIt at freenode, real-time chat

3fHNZJ.gif

Spoiler

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) intend to do that to anybody.

Share this post


Link to post
Share on other sites

@TheDcoder Well spotted! :) 

If $iIntType = $ARRAYUNIQUE_AUTO Then
    Local $vFirstElem = ( ($iDims = 1) ? $aArray[$iBase] : $aArray[$iBase][$iColumn] )
    Switch VarGetType($vFirstElem)
        Case "Int64"
            $iIntType = $ARRAYUNIQUE_FORCE64
        Case Else
            $iIntType = $ARRAYUNIQUE_FORCE32
    EndSwitch
EndIf

Edit: I'm a bit confused about the logic though. A float double could be greater than 0x7FFFFFFF, or less than 0x80000000. Perhaps I misunderstand the intention.

Edited by czardas

Share this post


Link to post
Share on other sites

@czardas

If $iIntType = $ARRAYUNIQUE_AUTO Then
    Local $vFirstElem = ( ($iDims = 1) ? $aArray[$iBase] : $aArray[$iBase][$iColumn] )
    If VarGetType($vFirstElem) = "Int64" Then
        $iIntType = $ARRAYUNIQUE_FORCE64
    Else
        $iIntType = $ARRAYUNIQUE_FORCE32
    EndIf
EndIf

:>


A cross-platform implementation of the AutoIt language

My contributions to the AutoIt Community ##AutoIt at freenode, real-time chat

3fHNZJ.gif

Spoiler

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) intend to do that to anybody.

Share this post


Link to post
Share on other sites

 

now doubles fall through and we save a couple of lines on your suggested solution above.

Just made the change in that way to prove my point and leave it to the others to come up with the best way to code this. (As is clearly demonstrate in the subsequent posts :) )
I mostly find pleasure in solving the "mystery". 

Jos  

 

Share this post


Link to post
Share on other sites

czardas,

I'm a bit confused about the logic though

Then re-read this thread (private forum).

 M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see 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

I looked at the current implementation. I still don't understand why you only want to test the first element, but the logic of the code is flawed regardless. An integer can be of three types. Conversion of doubles to integer datatypes can have two outcomes: Int-32 or Int-64.

Look at __DoubleTo64() in my operator64 (see sig). It's not a perfect solution, but you should see what I mean.

Edited by czardas

Share this post


Link to post
Share on other sites

czardas,

I still don't understand why you use only want to test the first element

The function cannot cope with every possible case (in a similar fashion to the _FileWritetoLine case we are discussing elsewhere), so the default assumption is made that the elements to be "uniqued" are all of the same datatype. So when the default $ARRAYUNIQUE_AUTO parameter is used, the function looks at the first element to be "uniqued" and determines its datatype. If the element is an Int64 then the function uses the slower algorithm and errors if it finds any Int32 elements - in all other cases it runs the fast algorithm and errors if it finds any Int64 elements. The user can override this by using the other parameters as explained In the Help file. We are forced into having 2 algorithms by the inability of the scripting object to accept Int64 keys and wanting to run the function as fast as possible - the "slow" algorithm being very significantly slower.

If you think this logic is flawed then please do explain why.

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see 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

I added a comment about doubles to my last post. This is the function I mentioned.

; #INTERNAL_USE_ONLY# ==========================================================================================================
; Name...........: __DoubleTo64
; Description ...: Helper function - converts an integer value double to Int-32 or Int-64.
; Syntax.........: __DoubleTo64($nValue)
; Parameters.....; $nValue - The double to convert
; Return values .: Success returns Int-32 or Int-64 when the interpreter evaluates the converted double equal to the input.
;                  Failure returns the input parameter without any modification and sets the following flags:
;                  |@error = 3 Internal error (x2) ==> see comments in the code.
;                  |@extended = 2 Conversion failed ==> the return value is not an integer.
; Author ........: czardas
; Comments ......; Doubles representing integer values greater than 15 digits cannot be relied on for accuracy.
; ==============================================================================================================================

Func __DoubleTo64($nValue)
    If Not IsNumber($nValue) Then Return SetError(3, 2, $nValue) ; the input is not a number.
    If $nValue > -1.0e+015 And $nValue < 1.0e+015 Then
        Local $iVal64 = Number($nValue, 2) ; convert to Int-64
        If $iVal64 = $nValue Then ; check to see if conversion was a success [expected range +/- 5.62949953421311e+014]
            Return ($iVal64 > 2147483647 Or $iVal64 < -2147483648) ? $iVal64 : Number($iVal64, 1) ; Int-64 or Int-32
        ElseIf $iVal64 -1 = $nValue Then ; attempt to adjust for inaccuracies [subject to possible change]
            Return $iVal64 -1
        ElseIf $iVal64 +1 = $nValue Then ; as above
            Return $iVal64 +1
        EndIf
    EndIf

    Return SetError(3, 2, $nValue) ; conversion failed
EndFunc ;==> __DoubleTo64

If you automatically assume Int-32 for an integer that is not Int-64, I guess it will max out on a large percentage of doubles.

Edited by czardas

Share this post


Link to post
Share on other sites

czardas,

There has to be a balance between user convenience and the function's ability to cover every possible edge case. As the Help file explains, if the user knows (or even suspects) that there are large double values involved then they can set the $iIntType parameter to use the slower algorithm and thus not force any integer-value doubles into Int32. Getting the function to check every element in an attempt to determine the correct fashion to deal with the contents of an array will make it even slower than it already is.

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see 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

I haven't used the scripting object method, so I will take your word for it. My suggested corrections to that line would be:

If $iIntType = $ARRAYUNIQUE_AUTO Then
    Local $vFirstElem = ( ($iDims = 1) ? $aArray[$iBase] : $aArray[$iBase][$iColumn] )
    If VarGetType($vFirstElem) = "Int64" Or $vFirstElem > 0x7FFFFFFF Or $vFirstElem < 0x80000000 Then
        $iIntType = $ARRAYUNIQUE_FORCE64
    Else
        $iIntType = $ARRAYUNIQUE_FORCE32
    EndIf
EndIf

This shouldn't add any significant delay, other than when it is actually needed (but it's obviously not foolproof).

Edited by czardas

Share this post


Link to post
Share on other sites

I'd make it do as little as possible to produce the desired results and leave the edge cases to the person writing their script to overcome the limitations. There seems to be a function inflation in regards to every UDF these days that just shouldn't be done. They're used as a library function, they shouldn't be customized to every user's whim. Get them, the included UDFs, doing the basics, and leave the inflation to the user's to devise their own functions.


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

Large integer doubles are not exactly what I would call edge cases. As soon as you use the division operator, you get a double. That being said, I agree that a compromise has to be made somewhere. Recursively looping through multidimensional arrays contained within the elements of other arrays to test all elements within a main (non-unique) array would be taking things way too far IMO.

Edited by czardas

Share this post


Link to post
Share on other sites

My comment wasn't referencing yours, its in reference to the whole thread heading towards the function being redone to accommodate the oddest of cases instead of leaving it alone and letting it do what it's supposed to do with the standard functionality. As I said, let the edge cases be handled by the person writing the script if they want it, library functions shouldn't be handling EVERY possible possibility.


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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • 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 
    • By Massi
      Hi, I have update to the most recent Autoit version. I have a little problem with _ArrayUnique function.
      If I have one array with two rows. _ArrayUnique crashes. I haven't any problem if there are more than two rows. I know that seems useless use this function with two rows, but these rows are the result of a search (generally I have more than two rows).
      "C:\Program Files (x86)\AutoIt3\Include\Array.au3" (2290) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
      Local $vFirstElem = ( ($iDims = 1) ? ($aArray[$iBase]) : ($aArray[$iColumn][$iBase]) )
      Local $vFirstElem = ( ($iDims = 1) ? ($aArray[$iBase]) : (^ ERROR
       
      #include <Array.au3> Dim $Test1[3][6]=[["11","12","13","14","15","16"],["21","22","23","24","25","26"],["21","22","23","24","25","26"]] Dim $Test[2][6]=[["11","12","13","14","15","16"],["21","22","23","24","25","26"]] Dim $result=0 _ArrayDisplay($Test1) _ArrayDisplay(_ArrayUnique($Test1, 2)) _ArrayDisplay($Test) _ArrayDisplay(_ArrayUnique($Test, 2)) I put a workaround that I don't use _ArrayUnique function if there are only two results
    • By czardas
      This seems currently a hot topic. Anyway I have been thinking of trying out this idea for a while. This is in experimental stage and uses an old idea of declaring uniquely named variables followed by testing for their existence. I always thought it was an interesting approach. You can set the second parameter to case sensitive. R stands for Row. It returns either a one dimensional array or a two dimensional array of unique rows. Three datatypes are ignored: namely nested arrays, objects and DLLstructs. If someone knows a way to test these items quickly for uniqueness, or represent the data as binary then please enlighten me. Rows containing these items are simply just left in place. I'm not sure how efficient or what limitations this code has. Testing begins in the morning - oh, it already is morning. Meanwhile you might like to have a play with it.
      ; #FUNCTION# =================================================================================================================== ; Name...........: _ArrayUniqueR ; Description ...: Removes duplicate items (or rows) from a one (or two) dimensional array. ; Syntax.........: _ArrayUniqueR($aArray [, $bCaseSense = False]) ; Parameters.....; $aArray - The array containing duplicate data to be removed. ; Return values .: Success - Returns the unique array [ByRef]. ; $bCaseSense - [Optional] Set to true for case sensitive matches. Default value = False ; Failure sets @error as follows ; |@error = 1 1st parameter is not an array. ; |@error = 2 1st parameter has too many dimensions. ; Author ........: czardas ; Comments ......; Works with strings, numbers, binary, boolean values, pointers, functions and keywords (Null and Default). ; Integers of the same magnitude are treated as duplicates regardless of data type. ; All elements within a row must be duplicated (in the same positions) before removal takes place. ; This function does not remove rows containing objects, DLLStructs or other arrays. ; If you modify _ArrayUniqueR, avoid using variable names that could collide with internally generated names. ; ============================================================================================================================== Func _ArrayUniqueR(ByRef $aArray, $bCaseSense = Default) If Not IsArray($aArray) Then Return SetError(1) ; not an array Local $iDim = UBound($aArray, 0) If $iDim > 2 Then Return SetError(2) ; wrong number of dimensions Local $iRows = UBound($aArray) If $iRows < 2 Then Return ; array is already unique If $bCaseSense = Default Then $bCaseSense = False Local $iCols = ($iDim = 1) ? 1 : UBound($aArray, 2), _ $iItems = 0, $aFunction[1] = [0], $vElement, $iInt, $sName ; for each item, or row, generate unique names using word characters only For $i = 0 To $iRows -1 $sName = '' ; clear previous name For $j = 0 To $iCols -1 $vElement = ($iDim = 1) ? $aArray[$i] : $aArray[$i][$j] ; get the data contained in each element ; use non-hexadecimal characters (other than x) as datatype identifiers and convert the data to hexadecimal where necessary Switch VarGetType($vElement) Case 'String' If Not $bCaseSense Then $vElement = StringUpper($vElement) ; generates a case insensitive name segment $sName &= 's' & StringToBinary($vElement, 4) ; UTF8 [$SB_UTF8] Case 'Int32', 'Int64' ; use decimal without conversion ; the minus sign of a negative integer is replaced with 'g': to distinguish it from the positive value $sName &= ($vElement < 0) ? 'g' & StringTrimLeft($vElement, 1) : 'i' & $vElement Case 'Double' ; may be an integer $iInt = Int($vElement) $sName &= ($vElement = $iInt) ? (($iInt < 0) ? 'g' & StringTrimLeft($iInt, 1) : 'i' & $iInt) : 'h' & Hex($vElement) Case 'Bool' ; True or False $sName &= ($vElement = True) ? 't' : 'v' Case 'Binary' $sName &= 'y' & $vElement Case 'Ptr' $sName &= 'p' & $vElement Case 'Keyword' ; Default or Null (other variable declarations are illegal) $sName &= ($vElement = Default) ? 'w' : 'n' Case 'Function', 'UserFunction' ; string conversion will fail For $k = 1 To $aFunction[0] ; unique functions are stored in a separate array If $vElement = $aFunction[$k] Then ; this function has been encountered previously $sName &= 'u' & $k ContinueLoop 2 EndIf Next $aFunction[0] += 1 If $aFunction[0] > UBound($aFunction) -1 Then ReDim $aFunction[$aFunction[0] + 10] $aFunction[$aFunction[0]] = $vElement $sName &= 'u' & $aFunction[0] Case Else ; Array, Object or DLLStruct $sName = False ; set to ignore ExitLoop EndSwitch Next If $sName Then If IsDeclared($sName) = -1 Then ContinueLoop ; [$DECLARED_LOCAL] this row has been seen previously Assign($sName, "", 1) ; [else] declare each unique row as a new variable name EndIf ; overwrite the next row (assumes that the first duplicate will be found quite quickly) Switch $iDim Case 1 $aArray[$iItems] = $aArray[$i] Case 2 For $j = 0 To $iCols -1 $aArray[$iItems][$j] = $aArray[$i][$j] Next EndSwitch $iItems += 1 Next Switch $iDim Case 1 ReDim $aArray[$iItems] Case 2 ReDim $aArray[$iItems][$iCols] EndSwitch EndFunc ;==> _ArrayUniqueR Example:
      #include <Array.au3> Local $aOddMix[14] = [Null, Null, True, True, False, False, Default, Default, Binary('0x0001'), Binary('0x0001'), Ptr(0x0001), Ptr(0x0001), MsgBox, MsgBox] _ArrayDisplay($aOddMix) $aUnique = _ArrayUniqueR($aOddMix) _ArrayDisplay($aOddMix)  
    • By souldjer777
      Good Morning AutoIT Geniuses 

      I have version 3.3.14.1.
      I am experiencing an error with the default Array.au3 or _ArrayUnique 
      I believe it is with this single line in my au3 file...$aUniqueHostname = _ArrayUnique ($array01, 1)
      SendAndLog("GEN_CSVMinRowLimit01 - Started", $tempzipdir & '\' & $LogFileName01, True) ; CSV Minimum Row Limit (FYI - default was originally set to 5000) $array01 = $twoDarray MsgBox (0, "", "You are here 1") $aUniqueHostname = _ArrayUnique ($array01, 1) ; FYI - The program never makes it to here: MsgBox (0, "", "You are here 2") "C:\Program Files (x86)\AutoIt3\Include\array.au3" (2297) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
      If IsInt($aArray[$iBase]) Then
      If IsInt(^ ERROR
      ; Title .........: Array
      ; AutoIt Version : 3.3.14.1  
       ; Autocheck of first element
          If $iIntType = $ARRAYUNIQUE_AUTO Then
              If IsInt($aArray[$iBase]) Then
              ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
                  Switch VarGetType($aArray[$iBase])
                      Case "Int32"
                          $iIntType = $ARRAYUNIQUE_FORCE32
                      Case "Int64"
                          $iIntType = $ARRAYUNIQUE_FORCE64
                  EndSwitch
              Else
                  $iIntType = $ARRAYUNIQUE_FORCE32
              EndIf
          EndIf
      I don't believe I've ever seen an error in the default au3 files. Is this something I am doing wrong?
      I'm just trying to run my apps through the new version of AutoIT since the fix was put in for...
      AutoIt3Help.exe reworked and digitally signed I have looked at bug trackers...
      https://www.autoitscript.com/trac/autoit/ticket/3110
      https://www.autoitscript.com/trac/autoit/ticket/3078
      Is this related somehow - what version of AutoIT do you recommend I use?
      Thanks!
       
    • By Gibbo
      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
×
×
  • Create New...