ArrayUnique ohne Bug´s und Schneller

  • Hi Leute!

    Duch den Post Array Ergenisse nur 1 mal sind UEZ ;) , Großvater und ich auf Bugs gestoßen und bemerkt das die Funktion ziemlich langsam ist !

    Basteln Basteln Fertig.

    Updat: Bug behoben dank an Großvater

    Neue Versaion ArrayUnique:

    Spoiler anzeigen
    [autoit]

    ; #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
    ; $iFlag - flag = 0 (default), it acts each included in the delimiter character as a separator mark
    ; flag = 1, it is the entire separator string used as a separator mark
    ; flag = 2, turned off the return of the number in the first element. Thus, the array is 0-based.
    ; It has to be now UBound () the size of the array.
    ; 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 - Array dimension is invalid, should be an integer greater than 0
    ; Author ........: SmOke_N
    ; Modified.......: litlmike, [Kleiner & Großvater & UEZ (:.AutoIT.de.:)]
    ; Remarks .......:
    ; Related .......:
    ; Link ..........:
    ; Example .......: Yes
    ; ===============================================================================================================================
    Func __ArrayUnique(Const ByRef $aArray, $iDimension = 0, Const $iBase = 0, Const $iCase = 0, $vDelim = '|', Const $iFlag = 0)
    If Not IsArray($aArray) Or UBound($aArray, 0) > 2 Then Return SetError(1, 0, -1)
    If ($iFlag < 0 Or $iFlag > 2) Then Return SetError(3, 0, -2)
    If ($vDelim = '|' Or Not $vDelim) Then $vDelim = Chr(01)
    Local $iUboundDim = UBound($aArray)
    Local $sHold
    If Not UBound($aArray, 2) Then
    For $I = $iBase To $iUboundDim - 1
    If Not StringInStr($sHold & $vDelim, $vDelim & $aArray[$I] & $vDelim, $iCase) Then $sHold &= $vDelim & $aArray[$I]
    Next
    Else
    If ($iDimension > (UBound($aArray, 2) - 1) Or $iDimension < 0) Then Return SetError(3, 0, -2)
    For $I = $iBase To $iUboundDim - 1
    If Not StringInStr($sHold & $vDelim, $vDelim & $aArray[$I][$iDimension] & $vDelim, $iCase) Then $sHold &= $vDelim & $aArray[$I][$iDimension]
    Next
    EndIf
    If $sHold Then Return StringSplit(StringTrimLeft($sHold, StringLen($vDelim)), $vDelim, $iFlag)
    Return SetError(2, 0, 0)
    EndFunc ;==>__ArrayUnique

    [/autoit]

    Lg Kleiner

  • Wer ist denn UZE? :P

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    Dim $aNames[10][2] = [["Anton", 33], ["Berta", 15], ["Cäsar", 300], ["Dora", 24], ["Emil", 33], ["Friedrich", 57], ["Gustav", 53], ["Heinrich", 34], ["Ida", 13], ["Julius", 77]]
    Dim $aUnique[1000][2]
    For $I = 0 To Ubound($aUnique) - 1
    $r = Random(0, 9, 1)
    $aUnique[$I][0] = $aNames[$r][0]
    $aUnique[$I][1] = $aNames[$r][1]
    Next
    $test2 = _ArrayUnique3($aUnique)
    _ArrayDisplay($test2)

    [/autoit] [autoit][/autoit] [autoit]

    Func _ArrayUnique3(Const ByRef $aArray, $iDimension = 0, Const $iBase = 0, Const $iCase = 0, $vDelim = '|')
    If ($iDimension > 2) Or ($iDimension < 0) Then Return SetError(3, 0, -2)
    If Not IsArray($aArray) Then Return SetError(1, 0, -1)
    If ($vDelim = '|') Then $vDelim = Chr(01)
    Local $iUboundDim = UBound($aArray)
    Local $sHold
    If Not UBound($aArray, 2) Then
    For $I = $iBase To $iUboundDim - 1
    If Not StringInStr($sHold, $aArray[$I], $iCase) Then $sHold &= $aArray[$I] & $vDelim
    Next
    Else
    For $I = $iBase To $iUboundDim - 1
    If Not StringInStr($sHold, $aArray[$I][$iDimension], $iCase) Then $sHold &= $aArray[$I][$iDimension] & $vDelim
    Next
    EndIf
    If $sHold Then Return StringSplit(StringTrimRight($sHold, StringLen($vDelim)), $vDelim, 2)
    Return SetError(2, 0, 0)
    EndFunc

    [/autoit]

    Ich bekomme nur ein 1D Array zurück!

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Habe auch mal was gebastelt:

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    ;~ Dim $aNames[10][2] = [["Anton", ""], ["Berta", 15]]
    Dim $aNames[10] = ["Antonia", "Anton", "Cäsar", "Dora", "Emil", "Friedrich", "Gustav", "Heinrich", "Ida", "Julius"]

    [/autoit] [autoit][/autoit] [autoit]

    Dim $aUnique[100000]
    For $I = 0 To Ubound($aUnique) - 1
    $r = Random(0, 9, 1)
    $aUnique[$I] = $aNames[$r]
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $ts = TimerInit()
    $test = ArrayUnique($aUnique)
    $te = TimerDiff($ts)
    ConsoleWrite(Round($te, 2) & " ms." & @CRLF)
    _ArrayDisplay($test)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Dim $aNames[10][2] = [["Antonia", ""], ["Anton", ""], ["Cäsar", 300], ["Dora", 24], ["Emil", 33], ["Friedrich", 57], ["Gustav", 53], ["Heinrich", 34], ["Ida", 13], ["Julius", 77]]
    Dim $aUnique[100000][2]
    For $I = 0 To Ubound($aUnique) - 1
    $r = Random(0, 9, 1)
    $aUnique[$I][0] = $aNames[$r][0]
    $aUnique[$I][1] = $aNames[$r][1]
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $ts = TimerInit()
    $test = ArrayUnique($aUnique)
    $te = TimerDiff($ts)
    ConsoleWrite(Round($te, 2) & " ms." & @CRLF)
    _ArrayDisplay($test)

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# =====================================================================================================================
    ; Name.............: ArrayUnique
    ; Description ...: Returns the Unique Elements of a 1-dimensional or 2-dimensional array.
    ; Syntax...........: _ArrayUnique($aArray[, $iBase = 0, oBase = 0, $iCase = 0])
    ; Parameters ...: $aArray - The Array to use
    ; $iBase - [optional] Is the input Array 0-base or 1-base index. 0-base by default
    ; $oBase - [optional] Is the output 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
    ; Return values: Success - Returns a 1-dimensional or 2-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 - Array has more than 2 dimensions
    ; 3 - Array is already unique
    ; 4 - when source array is selected as one base but UBound(array) - 1 <> array[0] / array[0][0]
    ; 5 - Scripting.Dictionary cannot be created for 1D array unique code
    ; Author .........: UEZ 2010 for 2D-array, Yashied for 1D-array (modified by UEZ)
    ; Version ........: 0.96 Build 2010-11-20 Beta
    ; ================================================================================================================================
    Func ArrayUnique($aArray, $iBase = 0, $oBase = 0, $iCase = 0)
    If Not IsArray($aArray) Then Return SetError(1, 0, 0) ;not an array
    If UBound($aArray, 0) > 2 Then Return SetError(2, 0, 0) ;array is greater than a 2D array
    If UBound($aArray) = $iBase + 1 Then Return SetError(3, 0, $aArray) ;array is already unique because of only 1 element
    Local $dim = UBound($aArray, 2), $i
    If $dim Then ;2D array
    If $iBase And UBound($aArray) - 1 <> $aArray[0][0] Then Return SetError(4, 0, 0)
    Local $oD = ObjCreate('Scripting.Dictionary')
    If @error Then Return SetError(5, 0, 0)
    Local $i, $j, $k = $oBase, $l, $s, $aTmp, $flag, $sSep = Chr(01)
    Local $aUnique[UBound($aArray)][$dim]
    If Not $oBase Then $flag = 2
    For $i = $iBase To UBound($aArray) - 1
    For $j = 0 To $dim - 1
    $s &= $aArray[$i][$j] & $sSep
    Next
    If Not $oD.Exists($s) And StringLen($s) > 3 Then
    $oD.Add($s, $i)
    $aTmp = StringSplit(StringTrimRight($s, 1), $sSep, 2)
    For $l = 0 To $dim - 1
    $aUnique[$k][$l] = $aTmp[$l]
    Next
    $k += 1
    EndIf
    $s = ""
    Next
    $oD.RemoveAll
    If $k > 0 Then
    If $oBase Then $aUnique[0][0] = $k - 1
    ReDim $aUnique[$k][$dim]
    Else
    ReDim $aUnique[1][$dim]
    EndIf
    Else ;1D array
    If $iBase And UBound($aArray) - 1 <> $aArray[0] Then Return SetError(4, 0, 0)
    Local $sData = '', $sSep = ChrW(160), $flag
    For $i = $iBase To UBound($aArray) - 1
    If Not IsDeclared($aArray[$i] & '$') Then
    Assign($aArray[$i] & '$', 0, 1)
    $sData &= $aArray[$i] & $sSep
    EndIf
    Next
    If Not $oBase Then $flag = 2
    Local $aUnique = StringSplit(StringTrimRight($sData, 1), $sSep, $flag)
    EndIf
    Return SetError(0, 0, $aUnique)
    EndFunc ;==>ArrayUnique

    [/autoit]

    Sollte auch für 2D Arrays funzen!

    Gruß,
    UEZ

  • Hi!


    UEZ hab natürlich dich gemeint :D !

    Wie Nuts schon Schreibt laut Funktion soll ein 1D Array zurückgegeben werden.
    Davon ab ich habe ein Funktion geschriebne _ObjektAr2DDubDel die das selbe macht , auch 2D Array´s u. ein Extra das noch Sortiert wird , nur allein die Idee der Funktion ( Algo) die hinter _ArrayUnique steckt finde ich sehr schön, das in dieser Funktion von den Autoren überflüssige abfragen und schleifen eingebaut wurden kann ich nicht nachvollziehen aber gute.

    Lg Kleiner

  • Hallo Kleiner,

    etwas mehr Aufwand ist schon erforderlich und ein paar mehr Fehlerprüfungen sind auch nicht schlecht.

    Lass Deine Funktion mal mit diesem Beispiel laufen

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    ;~ Dim $aNames[10][2] = [["Anton", ""], ["Berta", 15]]
    Dim $aNames[10][2] = [["Anton", ""], ["Berta", 15], ["Bert", 300], ["Dora", 24], ["Emil", 33], ["Friedrich", 57], ["Gustav", 53], ["Heinrich", 34], ["Ida", 13], ["Julius", 77]]
    Dim $aUnique[10000][2]
    For $I = 0 To Ubound($aUnique) - 1
    $r = Random(0, 9, 1)
    $aUnique[$I][0] = $aNames[$r][0]
    $aUnique[$I][1] = $aNames[$r][1]
    Next
    $test = ArrayUnique($aNames)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $test = ' & $test & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    _ArrayDisplay($test)

    [/autoit]

    und schau mal, was dem armen Bert passiert. ;)


    Ich habe Deiner Funktion deshalb noch ein paar Ergänzungen zukommen lassen und mich dabei bemüht, so nah wie möglich am Original zu bleiben:

    Spoiler anzeigen
    [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _ArrayUnique
    ; Description ...: Returns the Unique Elements of a 1D or 2D array.
    ; Syntax.........: _ArrayUnique($aArray[, $iColumn = 1[, $iBase = 0[, $iCase = 0[, $vDelim = "|"]]]])
    ; Parameters ....: $aArray - The Array to use
    ; $iColumn - [optional] 1-based column index for the 2nd 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:
    ; |1 - Array is not valid.
    ; |2 - _ArrayUnique failed for some other reason
    ; |3 - Column index is invalid, should be an integer greater than 0
    ; Author ........: SmOke_N
    ; Modified.......: litlmike, [Kleiner & Großvater & UEZ (:.AutoIT.de.:)]
    ; Remarks .......:
    ; Related .......:
    ; Link ..........:
    ; Example .......: Yes
    ; ===============================================================================================================================
    Func __ArrayUnique(Const ByRef $aArray, Const $iColumn = 1, Const $iBase = 0, Const $iCase = 0, $vDelim = '|')
    ;Check to see if it is valid array
    If Not IsArray($aArray) Or UBound($aArray, 0) > 2 Then Return SetError(1, 0, 0)
    ;Check to see if dimension is valid
    If UBound($aArray, 0) = 2 And ($iColumn < 1 Or $iColumn > UBound($aArray, 2)) Then Return SetError(3, 0, 0)
    If ($vDelim = '|') Then $vDelim = Chr(01) ; by SmOke_N, modified by litlmike
    Local $iRows = UBound($aArray) ;Number of rows in the array
    Local $iLen = StringLen($vDelim) ;Length of delimiter
    Local $sHold = $vDelim ;String that holds the Unique array info
    If UBound($aArray, 0) = 1 Then
    ; 1D array
    For $I = $iBase To $iRows - 1
    ;If Not the case that the element is already in $sHold, then add it
    If Not StringInStr($sHold, $vDelim & $aArray[$I] & $vDelim, $iCase) Then $sHold &= $aArray[$I] & $vDelim
    Next
    Else
    ; 2D array
    For $I = $iBase To $iRows - 1
    ;If Not the case that the element is already in $sHold, then add it
    If Not StringInStr($sHold, $vDelim & $aArray[$I][$iColumn - 1] & $vDelim, $iCase) Then $sHold &= $aArray[$I][$iColumn - 1] & $vDelim
    Next
    EndIf
    If StringLen($sHold) > $iLen Then Return StringSplit(StringMid($sHold, $iLen + 1, StringLen($sHold) - $iLen * 2), $vDelim, 2 - $iBase) ; <-- 2 - $iBase by UEZ
    Return SetError(2, 0, 0) ;If the script gets this far, it has failed
    EndFunc ;==>__ArrayUnique

    [/autoit]
  • Hi!

    @Großvater
    Stimmt , alt so viel hättes du nicht machen brauchen, Eine Variable zu abfrage reicht - $vDelim ich habe noch $iFlag für die Entscheidung ob o. Ohne Counter.
    Ich frage mich $iBase zu nehmen, denn meines erachtens nach ist $iBase für den Startindex und nicht für die Entscheidung Counter oder nicht ?Fraglich?

    Danke dir geändert Post#1!

    Lg Kleiner

  • Eine Variable zu abfrage reicht


    ... das stimmt leider nicht immer. Probier mal:

    [autoit]

    #include <Array.au3>
    Dim $Array[4] = ["Maus", "aus", "us", "s"]
    $aTemp = __ArrayUnique($Array)
    _ArrayDisplay($aTemp, "Huch!")

    [/autoit]
  • Hallo Kleiner,

    warum vertraust Du mir denn nicht? ;)

    [autoit]

    #include <Array.au3>
    Dim $Array[5] = ["Maus", "Maus", "aus", "us", "s"]
    $aTemp = __ArrayUnique($Array)
    _ArrayDisplay($aTemp, "Huch!")

    [/autoit]