array negativ sortieren

  • Ich wusste nicht genau wie ich es nennen sollte. Ich glaube das könnte schon irgendwie treffen.
    Mein problem ist das ich eine große liste habe aus der ich alle Einträge die doppelt sind herauslöschen möchte, so das nur die übrig bleiben die einfach vorkommen.

    Beispiel:

    bla1
    bla1
    bla2
    bla3
    bla3

    In diesem Fall sollte in der fertigen liste NUR bla2 stehen.
    Ich habe versucht das so zu lösen:

    [autoit]

    #include <array.au3>
    #include <File.au3>

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

    Dim $sFilePath = "check.txt"
    Dim $aContent
    Dim $newfile = "double.txt"

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

    _FileReadToArray($sFilePath, $aContent)
    _ArraySort($aContent,0,1)
    Dim $aArrayTmp[1]

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

    For $j = 1 To $aContent[0]-1
    If $aContent[$j] = $aContent[$j+1] Then
    Else
    _ArrayAdd($aArrayTmp, $aContent[$j])
    EndIf
    Next
    _FileWriteFromArray($newfile, $aArrayTmp)

    [/autoit]

    Ich verstehe nicht warum das nicht klappt ... am ende gibt er mir eine liste raus die halb so groß ist wie die alte. Und leider kann das nicht stimmen, da in der liste die ich durchgehen will nur ein paar Einträge einfach vorkommen.

    Eigentlich sollte das vom Prinzip her doch so gehen? Ich sortiere den array, dadurch stehen die doppelten Einträge alle untereinander. Also muss ich nur noch das obere mit dem unteren vergleichen und gut ists?


    Ich bitte um Hilfe hierbei. Ist warscheinlich ein ganz simpler fehler den ich nur gerade nicht sehe ..? :)

    lg
    Leo.1906

    Einmal editiert, zuletzt von Leo.1906 (16. März 2014 um 16:02)

  • Falls du wirklich doppelte Elemente komplett entfernen möchtest, dann kannst du diese Version deines Ansatzes verwenden:

    Spoiler anzeigen
    [autoit]

    #include <array.au3>
    #include <File.au3>

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

    Global $sFilePath = "check.txt", $sNewfile = "double.txt"
    Global $aContent, $aArrayTmp[1] = [0]

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

    _FileReadToArray($sFilePath, $aContent)
    _ArraySort($aContent,0,1)
    _ArrayDisplay($aContent)

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

    Global $bDuplicate
    For $i1 = 1 To $aContent[0]
    If $aContent[$i1] = "" Then ContinueLoop
    $bDuplicate = False
    For $i2 = $i1 + 1 To $aContent[0]
    If $aContent[$i1] == $aContent[$i2] Then
    $bDuplicate = True
    $aContent[$i2] = ""
    Else
    ExitLoop
    EndIf
    Next
    If $bDuplicate Then
    $aContent[$i1] = ""
    Else
    _ArrayAdd($aArrayTmp, $aContent[$i1])
    $aArrayTmp[0] += 1
    EndIf
    Next
    _FileWriteFromArray($sNewfile, $aArrayTmp)

    [/autoit]


    Ich habe einige Denkfehlfer korrigiert und das Script ein wenig aufgeräumt.

    Wenn du allerdings nur doppelte Elemente entfernen möchtest, so dass sie nur einmal vorhanden sind, dann gibt es die Funktion _ArrayUnique für diese Zwecke.

  • Moin!
    Hier mein Vorschlag:

    Ich habe _ArrayUnique so erweitert, dass es 3 unterschiedliche Funktionen hat (je nach Argument):
    1. Entfernung aller mehrfach auftretenden Elemente (wie _ArrayUnique)
    2. Anzeige der entfernten Elemente
    3. Entfernung aller Elemente, die nicht einzigartig sind (das, was du suchst)

    Das Ganze hab' ich mal dreist _ArrayUniqueEx genannt:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

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

    Global $ii = 0, $aArray[100]
    For $i = 0 To 99
    Switch $ii
    Case 0
    $aArray[$i] = "Einzigartig"
    Case 1
    $aArray[$i] = "Zweizigartig"
    Case 2
    $aArray[$i] = "Dreizigartig"
    Case 3
    $aArray[$i] = StringFormat("%02s Absolut Einzig", $i)
    $ii = -1
    EndSwitch
    $ii += 1
    Next

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

    _ArrayDisplay($aArray, "Orginal Array")
    $aUniqueEx = _ArrayUniqueEx($aArray) ;==> entfernt mehrfache Elemente (wie _ArrayUnique)
    _ArrayDisplay($aUniqueEx, "ArrayUnique")
    $aUniqueEx = _ArrayUniqueEx($aArray, 1) ;==> liefert Array mit den entfernten Elementen zurück
    _ArrayDisplay($aUniqueEx, "Entfernte Elemente")
    $aUniqueEx = _ArrayUniqueEx($aArray, 2) ;==> liefert Array mit den einzigartigen Elementen zurück
    _ArrayDisplay($aUniqueEx, "Einzigartige Elemente")

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

    Func _ArrayUniqueEx($aArrayTemp, $iType = 0, $iStartIndex = 0) ;_ArrayUnique mod by FRiESEL
    If $iType = -1 Then $iType = 0
    If $iType <> 0 And $iType <> 1 And $iType <> 2 Then Return SetError(1, 0, 0)
    Local $vDelim = Chr(01), $sHold, $sHoldDouble, $sHoldSingle
    For $i = $iStartIndex To UBound($aArrayTemp) - 1
    If Not StringInStr($vDelim & $sHold, $vDelim & $aArrayTemp[$i] & $vDelim) Then
    $sHold &= $aArrayTemp[$i] & $vDelim
    Else
    $sHoldDouble &= $aArrayTemp[$i] & $vDelim
    EndIf
    Next
    For $i = $iStartIndex To UBound($aArrayTemp) - 1
    If Not StringInStr($vDelim & $sHoldDouble, $vDelim & $aArrayTemp[$i] & $vDelim) Then
    $sHoldSingle &= $aArrayTemp[$i] & $vDelim
    EndIf
    Next
    Switch $iType
    Case 0
    If $sHold Then $aArrayTemp = StringSplit(StringTrimRight($sHold, StringLen($vDelim)), $vDelim, 1)
    Case 1
    If $sHoldDouble Then $aArrayTemp = StringSplit(StringTrimRight($sHoldDouble, StringLen($vDelim)), $vDelim, 1)
    Case 2
    If $sHoldSingle Then $aArrayTemp = StringSplit(StringTrimRight($sHoldSingle, StringLen($vDelim)), $vDelim, 1)
    EndSwitch
    Return $aArrayTemp
    EndFunc ;==>_ArrayUniqueEx

    [/autoit]

    Mit _FileReadToArray wie in deinem Beispiel würde das dann so aussehen:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    #include <File.au3>

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

    Global $sFilePath = "check.txt", $sNewfile = "double.txt"
    Global $aArray

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

    _FileReadToArray($sFilePath, $aArray)
    _ArraySort($aArray,0,1)
    _ArrayDisplay($aArray)

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

    $aUniqueEx = _ArrayUniqueEx($aArray, 2, 1) ;==> liefert Array mit den einzigartigen Elementen zurück
    _ArrayDisplay($aUniqueEx, "Einzigartige Elemente")

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

    _FileWriteFromArray($sNewfile, $aUniqueEx, 1)

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

    Func _ArrayUniqueEx($aArrayTemp, $iType = 0, $iStartIndex = 0) ;_ArrayUnique mod by FRiESEL
    If $iType = -1 Then $iType = 0
    If $iType <> 0 And $iType <> 1 And $iType <> 2 Then Return SetError(1, 0, 0)
    Local $vDelim = Chr(01), $sHold, $sHoldDouble, $sHoldSingle
    For $i = $iStartIndex To UBound($aArrayTemp) - 1
    If Not StringInStr($vDelim & $sHold, $vDelim & $aArrayTemp[$i] & $vDelim) Then
    $sHold &= $aArrayTemp[$i] & $vDelim
    Else
    $sHoldDouble &= $aArrayTemp[$i] & $vDelim
    EndIf
    Next
    For $i = $iStartIndex To UBound($aArrayTemp) - 1
    If Not StringInStr($vDelim & $sHoldDouble, $vDelim & $aArrayTemp[$i] & $vDelim) Then
    $sHoldSingle &= $aArrayTemp[$i] & $vDelim
    EndIf
    Next
    Switch $iType
    Case 0
    If $sHold Then $aArrayTemp = StringSplit(StringTrimRight($sHold, StringLen($vDelim)), $vDelim, 1)
    Case 1
    If $sHoldDouble Then $aArrayTemp = StringSplit(StringTrimRight($sHoldDouble, StringLen($vDelim)), $vDelim, 1)
    Case 2
    If $sHoldSingle Then $aArrayTemp = StringSplit(StringTrimRight($sHoldSingle, StringLen($vDelim)), $vDelim, 1)
    EndSwitch
    Return $aArrayTemp
    EndFunc ;==>_ArrayUniqueEx

    [/autoit]

    Sanfte Grüße :D

  • Ich habe einmal etwas ähnliches geschrieben, dabei ging es nicht ums entfernen der mehrfach auftretenden Einträge, sondern um die Anzeige wie oft diese vorkommen. Hier eine modifizierte Fassung die alle Mehrfacheinträge auch entfernen kann:

    Spoiler anzeigen
    [autoit]


    #include <array.au3>

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

    Global $testArray[11] = ["WM_KILLFOCUS", "WM_KILLFOCUS", "WM_ENABLE", "WM_SETREDRAW", "UnMountMOM", "MountMOM", "WM_CLOSE", "WM_PAINT", "WM_SETREDRAW", "WM_SETREDRAW", "Mountmom"]

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

    $aUnique2D = _arrayUniqueCount($TestArray, 2) ; 2D Variante
    $aUnique1D = _arrayUniqueCount($TestArray, 1) ; 1D Variante mit geschweiften Klammern
    $aUnique1Drem = _arrayUniqueCount($TestArray, 3) ; doubletten entfernt
    $aUnique1DremNotCasesense = _arrayUniqueCount($TestArray, 3, 0) ; doubletten entfernt (auch bei unterschiedlicher Groß- Kleinschreibuung)

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

    _arraydisplay($aUnique2D,"2D Variante")
    _arraydisplay($aUnique1D,"1D Variante mit geschweiften Klammern")
    _ArrayDisplay($aUnique1Drem, 'Doubletten entfernt')
    _ArrayDisplay($aUnique1DremNotCasesense, 'Doubletten entfernt nicht casesensitiv')

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

    Func _arrayUniqueCount(ByRef $aData, $mode=2, $casesense=1, $sepChar=",") ; mode: 1 = 1D Rückgabe , 2 = 2D Rückgabe, 3 = Doubletten komplett entfernen

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

    If Not IsArray($aData) Then Return -1 ; wichtig: bitte Rückgabe dieser Funktion prüfen bevor weiter gearbeitet wird...

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

    Local $aNew[ubound($aData)][2] ; für 2D Rückgabe
    Local $aNew1D[1] ; für 1D Rückgabe
    Local $sTemp=$sepChar ; string verkettung des ergebnis arrays für schnelle unique prüfung
    Local $j=0 ; zahl der unique treffer

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

    For $i=0 To UBound($aData)-1
    If StringInStr($sTemp,$sepChar & $aData[$i] & $sepChar,$casesense,-1) Then ; stringprüfung arbeitet schneller als große arrays zu durchlaufen und "viele" strings zu vergleichen
    For $k=0 To UBound($aNew)-1 ; bei bereits vorhandenen einträgen müssen wir zwangsweise die bisherigen suchergebnisse durchlaufen um den korrekten index zu finden
    If $aNew[$k][0]=$aData[$i] Then
    $aNew[$k][1]+=1
    ExitLoop
    EndIf
    Next
    Else
    $aNew[$j][0] = $aData[$i]
    $aNew[$j][1] = 1
    $sTemp &= $aData[$i] & $sepChar
    $j += 1
    EndIf
    Next
    ReDim $aNew[$j][2]

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

    ; sofern zwingend ein 1D Array als Ausgabe benötigt wird muss das neue Array noch einmal durchlaufen werden:
    if $mode = 1 Then
    ReDim $aNew1D[UBound($aNew)]
    For $i=0 To UBound($aNew)-1
    If $aNew[$i][1] > 1 Then
    $aNew1D[$i]=$aNew[$i][0] & " {" & $aNew[$i][1] & "x}"
    Else
    $aNew1D[$i]=$aNew[$i][0]
    EndIf
    Next
    $aNew=$aNew1D
    EndIf

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

    if $mode = 3 Then
    ReDim $aNew1D[UBound($aNew)]
    $k = 0
    For $i=0 To UBound($aNew)-1
    If $aNew[$i][1] > 1 Then
    continueloop ; doppelte Einträge überspringen
    Else
    $aNew1D[$k]=$aNew[$i][0]
    $k += 1
    EndIf
    Next
    if $k > 0 Then
    ReDim $aNew1D[$k]
    Else
    Return -2 ; Achtung: Auf Fehlerrückgabe prüfen! Es gab keine einmalig auftretenden Einträge im Array
    EndIf
    $aNew=$aNew1D
    EndIf

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

    Return $aNew
    EndFunc

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

    Einmal editiert, zuletzt von misterspeed (15. März 2014 um 10:27)

  • Vielen Dank für die Antworten! Das klappt alles wirklich gut :)
    Ich hab jetzt aber doch noch ne andere Frage .. Ich wollte das eigentlich so haben das ich zwei Listen vergleiche und die neuen Einträge übernehme. Und zwar nur die neuen. Dafür hab ich die beiden listen halt in einen array geladen. Aber jetzt seh ich das da ein Denkfehler drin ist. Denn er vergleicht die listen in beide richtungen. Also wenn in der alten Liste etwas drin ist das in der neuen nicht mehr vorhanden ist, dann wird das auch als "neu" mit aufgelistet, was ich aber eigentlich nicht möchte .. :D
    Versteht ihr was ich meine? Wie kann man sowas lösen? Mir fällt dazu jetzt spontan nichts ein ... :/

  • Dann arbeite eben mit 2 Arrays und berücksichtige nur den gefilterten Inhalt des neuen Arrays.

    Beispiel:

    [autoit]


    #include <array.au3>

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

    global $aOld[4] = ["a","b","c","d"]
    global $aNew[5] = ["a","c","d","e","f"]
    global $aResult[1]

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

    ; b wurde gelöscht, e und f sind neu hinzugekommen

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

    $k = 0
    for $i = 0 to ubound($aNew)-1
    $skip = False
    for $j = 0 to ubound($aOld)-1
    if $aNew[$i]=$aOld[$j] then
    $skip = True ; das aktuelle Element des neue Arrays war schon im alten enthalten, also interessiert es uns nicht
    exitloop
    endif
    next
    if $skip = False then
    $aResult[$k] = $aNew[$i] ; das aktuelle Element des neuen Arrays ist wirklich neu und war noch nicht enthalten, also speichern wir es im result Array
    $k+=1
    redim $aResult[$k+1]
    endif
    next
    redim $aResult[$k]

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

    _arraydisplay($aresult)

    [/autoit]
  • Moin!

    Um meine Funktion auch wieder ins Spiel zu bringen, hier mein Vorschlag :party:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

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

    Global $aArray1[10]
    Global $aArray2[10]
    For $i = 0 To 9
    $aArray1[$i] = $i & " - Element"
    $aArray2[$i] = $i + 5 & " - Element"
    Next

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

    _ArrayDisplay($aArray1, "Erstes Array")
    _ArrayDisplay($aArray2, "Zweites Array")

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

    _ArrayConcatenate($aArray1, $aArray2)

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

    _ArrayDisplay($aArray1, "$aArray1 & $aArray2")

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

    $aUniqueEx = _ArrayUniqueEx($aArray1, 2)
    _ArrayDisplay($aUniqueEx, "Einzigartige Elemente")

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

    Func _ArrayUniqueEx($aArrayTemp, $iType = 0, $iStartIndex = 0) ;_ArrayUnique mod by FRiESEL
    If $iType = -1 Then $iType = 0
    If $iType <> 0 And $iType <> 1 And $iType <> 2 Then Return SetError(1, 0, 0)
    Local $vDelim = Chr(01), $sHold, $sHoldDouble, $sHoldSingle
    For $i = $iStartIndex To UBound($aArrayTemp) - 1
    If Not StringInStr($vDelim & $sHold, $vDelim & $aArrayTemp[$i] & $vDelim) Then
    $sHold &= $aArrayTemp[$i] & $vDelim
    Else
    $sHoldDouble &= $aArrayTemp[$i] & $vDelim
    EndIf
    Next
    For $i = $iStartIndex To UBound($aArrayTemp) - 1
    If Not StringInStr($vDelim & $sHoldDouble, $vDelim & $aArrayTemp[$i] & $vDelim) Then
    $sHoldSingle &= $aArrayTemp[$i] & $vDelim
    EndIf
    Next
    Switch $iType
    Case 0
    If $sHold Then $aArrayTemp = StringSplit(StringTrimRight($sHold, StringLen($vDelim)), $vDelim, 1)
    Case 1
    If $sHoldDouble Then $aArrayTemp = StringSplit(StringTrimRight($sHoldDouble, StringLen($vDelim)), $vDelim, 1)
    Case 2
    If $sHoldSingle Then $aArrayTemp = StringSplit(StringTrimRight($sHoldSingle, StringLen($vDelim)), $vDelim, 1)
    EndSwitch
    Return $aArrayTemp
    EndFunc ;==>_ArrayUniqueEx

    [/autoit]


    Sanfte Grüße :D