Jump to content

Recommended Posts

Posted

Hallo, i want to make a GUI with an inputfield to fill with different values separated by komma. I found this CodeSnippet here in this forum but it doesn't work and it does not eliminate the duplicates:

Local $arString=StringSplit("19,28,3,17,7",",")
;sorting the array
For $i=2 To UBound($arString)-1
    If Int($arString[$i-1])>Int($arString[$i]) Then _ArraySwap($arString[$i-1],$arString[$i])
Next

Thx furuseth

Posted (edited)

Use _ArrayUnique to get an array that only contains unique elements. I'm not sure but I think the array has to be sorted in advance.

As an example:

#include <array.au3>
Global $aSource[7] = [1,2,4,3,5,3,6]
Global $aTarget[7]

_ArraySort($aSource)
$aTarget = _ArrayUnique($aSource)
_ArrayDisplay($aTarget)
Edited by water

My UDFs and Tutorials:

  Reveal hidden contents

 

  • Moderators
Posted

furuseth,

Welcome to the AutoIt forum. :graduated:

One way to do it:

#include <GUIConstantsEx.au3>
#include <Array.au3>

$hGUI = GUICreate("Test", 500, 500)

$hInput = GUICtrlCreateInput("19,28,3,17,7", 10, 10, 400, 20)

$hButton = GUICtrlCreateButton("Go!", 10, 50, 80, 30)

GUISetState()

While 1

    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
        Case $hButton
            _Sort_Input()
    EndSwitch

WEnd

Func _Sort_Input()

    ; Read the input
    $sInputString = GUICtrlRead($hInput)
    ; Convert to an array and get unique elements
    $aOutArray = _ArrayUnique(StringSplit($sInputString, ","), 1, 1)
    ; Convert to numbers
    For $i = 1 To $aOutArray[0]
        $aOutArray[$i] = Number($aOutArray[$i])
    Next
    ; Sort the elements
     _ArraySort($aOutArray, 0, 1)
    ; Display array
    _ArrayDisplay($aOutArray)

EndFunc

Note that you have to convert the elements to numbers before sorting - otherwise you get an ASCII not a numeric sort. :D

Please ask if you have any questions. :(

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:

  Reveal hidden contents

 

Posted

Wow, thank you. They are working like a charme. The one of Melba23was exactly the snippet I need. One more question, how to get a sorted output string? For Example if the input was 19,28,3,17,7 the result should be 1 variable containing the sorted numbers: 3,7,17,19,28

Sorry for my stupid questions, I'm really newbie.

Thx furuseth

@Melba23 I'm honored; read so many of your threads in this forum.

Posted (edited)
  On 11/17/2010 at 9:44 AM, 'furuseth said:

One more question, how to get a sorted output string?

$sString = _ArrayToString($aOutArray, ",", 1) Edited by water

My UDFs and Tutorials:

  Reveal hidden contents

 

  • Moderators
Posted

furuseth,

Change the end of the function to read: :graduated:

; Sort the elements
_ArraySort($aOutArray, 0, 1)
; Return it to string format
$sOutputString = _ArrayToString($aOutArray, ",", 1)
; Display it
MsgBox(0, "Result", $sOutputString)

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:

  Reveal hidden contents

 

Posted (edited)

It seems to be that _ArrayUnique() has a bug and it is very slow:

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

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

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

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


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

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


Exit



; #FUNCTION# ============================================================================
; Name.............:    ArrayUnique
; Description ...:  Returns the Unique Elements of a 1-dimensional or 2-dimensional array.
; Syntax...........:    _ArrayUnique($aArray[, $iBase = 0, oBase = 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
; Return values:    Success - Returns a 1-dimensional or 2-dimensional array containing only the unique elements
;                           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)
    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
        $oD = ""
        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

It might be that my version has a bug, too! :graduated:

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted (edited)

This might be a way:

#include <Array.au3>

Dim $aNumbers[10] = [19, 22, 3, 9, 27, 22, 19, 99, 88, 3]
$aUnique = ArrayUnique($aNumbers)
_ArrayDisplay($aUnique)
_ArraySort($aUnique) ;standard sort not natural! Look here for natural order sorting: http://www.autoitscript.com/forum/topic/83626-natural-order-string-comparison/page__p__598311
_ArrayDisplay($aUnique)

Exit



; #FUNCTION# ============================================================================
; Name.............:    ArrayUnique
; Description ...:  Returns the Unique Elements of a 1-dimensional or 2-dimensional array.
; Syntax...........:    _ArrayUnique($aArray[, $iBase = 0, oBase = 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
; Return values:    Success - Returns a 1-dimensional or 2-dimensional array containing only the unique elements
;                           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)
    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
        $oD = ""
        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

Br,

UEZ

PS: where is the post between post#7 and post#8?

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted

  On 11/17/2010 at 11:21 AM, 'UEZ said:

[it might be that my version has a bug, too! :whistle:

Br,

UEZ

A very minor contribution on your faster version...

Shouldn't:

If UBound($aArray) + $iBase = $iBase + 1 Then Return SetError(3, 0, $aArray) ;array is already unique

be:

If UBound($aArray) = $iBase + 1 Then Return SetError(3, 0, $aArray) ;array only has one element
Posted

@Spiff59: indeed, it was a logical error. Posted Image

I corrected it!

I'm happy that somebody tested it!

Thank you very much Spiff59!

Br,

UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted (edited)

  On 11/19/2010 at 4:34 PM, 'UEZ said:

I'm happy that somebody tested it!

Br,

UEZ

You're welcome.

Just an idea, but considering that the Scripting.Dictionary is so blazing fast, couldn't it be implemented for your 2D routine as well? Like:

Func ArrayUnique2($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
    Local $oD = ObjCreate('Scripting.Dictionary')
    If @error Then Return SetError(4, 0, 0)
    Local $dim2 = UBound($aArray, 2), $i
    If $dim2 Then ;2D array
        Local $dim1 = UBound($aArray, 1), $aUnique[$dim1][$dim2], $j
        For $i = 0 to $dim1 - 1
            If Not $oD.Exists($aArray[$i][0]) Then
                $oD.Add($aArray[$i][0], 0)
                $aUnique[$j][0] = $aArray[$i][0]
                $aUnique[$j][1] = $aArray[$i][1]
                $j += 1
            EndIf
        Next
        ReDim $aUnique[$j][2]
    Else ;1D array
        For $i In $aArray
            If Not $oD.Exists($i) Then $oD.Add($i, 0)
        Next
        Local $aUnique = $oD.Keys()
    EndIf
    $oD.RemoveAll
    $oD = ""
    Return SetError(0, 0, $aUnique)
EndFunc

(I didn't add any of the handling for $IBase and $OBase, that were already missing from the 1D section).

Edit: Pardon me, OP, for potential thread-jacking :graduated:

Edited by Spiff59
Posted (edited)

  On 11/19/2010 at 6:28 PM, 'Spiff59 said:

You're welcome.

Just an idea, but considering that the Scripting.Dictionary is so blazing fast, couldn't it be implemented for your 2D routine as well? Like:

Func ArrayUnique2($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
    Local $oD = ObjCreate('Scripting.Dictionary')
    If @error Then Return SetError(4, 0, 0)
    Local $dim2 = UBound($aArray, 2), $i
    If $dim2 Then ;2D array
        Local $dim1 = UBound($aArray, 1), $aUnique[$dim1][$dim2], $j
        For $i = 0 to $dim1 - 1
            If Not $oD.Exists($aArray[$i][0]) Then
                $oD.Add($aArray[$i][0], 0)
                $aUnique[$j][0] = $aArray[$i][0]
                $aUnique[$j][1] = $aArray[$i][1]
                $j += 1
            EndIf
        Next
        ReDim $aUnique[$j][2]
    Else ;1D array
        For $i In $aArray
            If Not $oD.Exists($i) Then $oD.Add($i, 0)
        Next
        Local $aUnique = $oD.Keys()
    EndIf
    $oD.RemoveAll
    $oD = ""
    Return SetError(0, 0, $aUnique)
EndFunc

(I didn't add any of the handling for $IBase and $OBase, that were already missing from the 1D section).

Edit: Pardon me, OP, for potential thread-jacking :graduated:

Well, I updated my version with some more checks but after having it bug free I wanted to implement the 2D part also with Scripting.Dictionary because I started first with 2D arrays and found the Scripting.Dictionary method afterwards which is very fast. I mixed up both versions as a start but you did already my next step! Posted Image

I will do some more checks with your version and then let's see... Posted Image

Thanks again Spiff59!

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted (edited)

@UEZ

You do not need to use COM, simply Assign()...

#Include <Array.au3>

Global $aUnique

Dim $aNames[10] = ['Antonia', 'Anton', 'Casar', 'Dora', 'Emil', 'Friedrich', 'Gustav', 'Heinrich', 'Ida', 'Julius']

Dim $aArray[10000]
For $i = 0 To UBound($aArray) - 1
    $aArray[$i] = $aNames[Random(0, 9, 1)]
Next

_ArrayUniqueFast($aArray, $aUnique)
_ArrayDisplay($aUnique)

Func _ArrayUniqueFast(Const ByRef $aArray, ByRef $aUnique)

    Local $sData = '', $sSep = ChrW(160)

    For $i = 0 To UBound($aArray) - 1
        If Not IsDeclared($aArray[$i] & '$') Then
            Assign($aArray[$i] & '$', 0, 1)
            $sData &= $aArray[$i] & $sSep
        EndIf
    Next
    $aUnique = StringSplit(StringTrimRight($sData, 1), $sSep)
EndFunc   ;==>_ArrayUniqueFast
Edited by Yashied
Posted (edited)

Great idea Yashied! Posted Image

I thought that COM is the fastest for 1D array but you have beaten it to the factor ~3!

Well done! Posted Image

I updated my codes above.

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

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
  • Recently Browsing   0 members

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