Schnittmengen und Differenzmengen ermitteln

    • Offizieller Beitrag

    Hi,
    es kommt häufiger vor, dass wir 2 verschiedene Mengen haben, die untersucht werden müssen auf gemeinsame oder unterschiedliche Elemente (Vergleichen von Arrays oder Strings).
    Mit der Funktion _GetIntersection( ) werden aus 2 gegebenen Mengen,
    - die als 1D-Array oder Trennzeichenbasierter String übergeben werden
    - die Schnittmenge (gemeinsame Elemente)
    - die Differenzmenge 1 (nur in Menge 1 enthaltene Elemente) und
    - die Differenzmenge 2 (nur in Menge 2 enthaltene Elemente) ermittelt.
    - mehrfach vorkommende Elemente werden nur 1-mal ausgegeben
    - mehrfach vorkommende Elemente der Differenzmengen werden wahlweise kpl. oder 1-mal ausgegeben
    - der Vergleich ist Case-Sensitiv, also [9] <> '9'
    - Rückgabe erfolgt in einem 2D-Array ([n][0]=Schnittmenge; [n][1]=Diff1; [n][2]=Diff2)

    EDIT: Differenzmengen wahlweise komplett oder einmalig zurückgeben

    EDIT 14.10.2008
    - für $Delim wird als Standard 'Default' verwendet und damit das Trennzeichen aus Opt("GUIDataSeparatorChar")
    - gefixed: Fehler bei Verwendung von @CRLF alsTrennzeichen

    _GetIntersection( )
    [autoit]

    #include <array.au3>
    Local $1 = '1,1,2,3,3,3,4,4,5,6,7'
    Local $2[10] = ['5','5','5','8','8','9','12','12','3','1']

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

    Local $ret = _GetIntersection($1, $2, 0, ',')
    If IsArray($ret) Then _ArrayDisplay($ret)

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

    Local $ret = _GetIntersection($1, $2, 1, ',')
    If IsArray($ret) Then _ArrayDisplay($ret)

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

    ;==================================================================================================
    ; Function Name: _GetIntersection($Set1, $Set2 [, $GetAll=0 [, $Delim=Default]])
    ; Description:: Aus 2 gegebenen Mengen werden ermittelt
    ; - die Schnittmenge (Elemente, die in beiden Mengen enthalten sind)
    ; - die Differenzmenge 1 (Elemente, die nur in Menge 1 vorkommen)
    ; - die Differenzmenge 2 (Elemente, die nur in Menge 2 vorkommen)
    ; Parameter(s): $Set1 Menge 1 (1D-Array od. Trennzeichenbasierter String)
    ; $Set2 Menge 2 (1D-Array od. Trennzeichenbasierter String)
    ; optional: $GetAll 0 - mehrfach vorhandenen Elemente der Differenzmengen werden einmalig ausgegeben (Standard)
    ; 1 - mehrfach vorhandenen Elemente der Differenzmengen werden komplett ausgegeben
    ; optional: $Delim Trennzeichen für String (Standard 'Default' nutzt Zeichen aus Opt("GUIDataSeparatorChar"))
    ; Return Value(s): Erfolg 2D-Array [i][0]=Schnittmenge
    ; [i][1]=Differenzmenge 1
    ; [i][2]=Differenzmenge 2
    ; Fehler -1 @error als Array übergebene Menge ist kein 1D-Array
    ; Note: Der Vergleich ist Case-Sensitiv! - Ein Array-Element [9] ist also <> String '9'!!
    ; Author(s): BugFix ([email='bugfix@autoit.de'][/email])
    ;==================================================================================================
    Func _GetIntersection(ByRef $Set1, ByRef $Set2, $GetAll=0, $Delim=Default)
    Local $o1 = ObjCreate("System.Collections.ArrayList")
    Local $o2 = ObjCreate("System.Collections.ArrayList")
    Local $oUnion = ObjCreate("System.Collections.ArrayList")
    Local $oDiff1 = ObjCreate("System.Collections.ArrayList")
    Local $oDiff2 = ObjCreate("System.Collections.ArrayList")
    Local $tmp, $i
    If $GetAll <> 1 Then $GetAll = 0
    If $Delim = Default Then $Delim = Opt("GUIDataSeparatorChar")
    If Not IsArray($Set1) Then
    If Not StringInStr($Set1, $Delim) Then
    $o1.Add($Set1)
    Else
    $tmp = StringSplit($Set1, $Delim, 1)
    For $i = 1 To UBound($tmp) -1
    $o1.Add($tmp[$i])
    Next
    EndIf
    Else
    If UBound($Set1, 0) > 1 Then Return SetError(1,0,-1)
    For $i = 0 To UBound($Set1) -1
    $o1.Add($Set1[$i])
    Next
    EndIf
    If Not IsArray($Set2) Then
    If Not StringInStr($Set2, $Delim) Then
    $o2.Add($Set2)
    Else
    $tmp = StringSplit($Set2, $Delim, 1)
    For $i = 1 To UBound($tmp) -1
    $o2.Add($tmp[$i])
    Next
    EndIf
    Else
    If UBound($Set2, 0) > 1 Then Return SetError(1,0,-1)
    For $i = 0 To UBound($Set2) -1
    $o2.Add($Set2[$i])
    Next
    EndIf
    For $tmp In $o1
    If $o2.Contains($tmp) And (Not $oUnion.Contains($tmp)) Then $oUnion.Add($tmp)
    Next
    For $tmp In $o2
    If $o1.Contains($tmp) And (Not $oUnion.Contains($tmp)) Then $oUnion.Add($tmp)
    Next
    For $tmp In $o1
    If $GetAll Then
    If Not $oUnion.Contains($tmp) Then $oDiff1.Add($tmp)
    Else
    If Not $oUnion.Contains($tmp) And Not $oDiff1.Contains($tmp) Then $oDiff1.Add($tmp)
    EndIf
    Next
    For $tmp In $o2
    If $GetAll Then
    If Not $oUnion.Contains($tmp) Then $oDiff2.Add($tmp)
    Else
    If Not $oUnion.Contains($tmp) And Not $oDiff2.Contains($tmp) Then $oDiff2.Add($tmp)
    EndIf
    Next
    Local $UBound[3] = [$oDiff1.Count,$oDiff2.Count,$oUnion.Count], $max = 1
    For $i = 0 To UBound($UBound) -1
    If $UBound[$i] > $max Then $max = $UBound[$i]
    Next
    Local $aOut[$max][3]
    If $oUnion.Count > 0 Then
    $i = 0
    For $tmp In $oUnion
    $aOut[$i][0] = $tmp
    $i += 1
    Next
    EndIf
    If $oDiff1.Count > 0 Then
    $i = 0
    For $tmp In $oDiff1
    $aOut[$i][1] = $tmp
    $i += 1
    Next
    EndIf
    If $oDiff2.Count > 0 Then
    $i = 0
    For $tmp In $oDiff2
    $aOut[$i][2] = $tmp
    $i += 1
    Next
    EndIf
    Return $aOut
    EndFunc ;==>_GetIntersection

    [/autoit]
    • Offizieller Beitrag

    Hi,
    nochmal ergänzend, damit klarer wird, wozu die Funktion taugt, ein Beispiel zum Vergleich von Texten.
    Ich vergleiche 2 weitgehend identische Texte, im zweiten Fall habe ich ein paar "Schreibfehler" eingebaut. Diese Unterschiede zu Text1 werden dann ermittelt.
    So lassen sich Unterschiede und Gemeinsamkeiten von Arrays und Strings ermitteln.

    Spoiler anzeigen
    [autoit]

    Local $txt1 = _
    'Gerhard Fritz Kurt Schröder (oft genannt Gerd; * 7. April 1944 in Mossenberg, heute Ortsteil von Blomberg, Kreis Lippe) ist ein deutscher SPD-Politiker. ' & _
    'Er war von 1998 bis 2005 Bundeskanzler der Bundesrepublik Deutschland sowie zuvor von 1990 bis 1998 Ministerpräsident des Landes Niedersachsen. ' & _
    'Nach seiner politischen Karriere wechselte Schröder in die Wirtschaft, wo er bis heute verschiedene Positionen bekleidet.' & _
    'Während und nach seiner Kanzlerschaft wurden und werden die Anhänger von Schröders Agenda 2010 auch „Schröderianer“ genannt.'

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

    Local $txt2 = _
    'Gerhard Fritz Kurt Schröder (oft genannt Gerd; * 7. April 1945 in Mossenberg, heute Ortsteil von Blumberg, Kreis Lippe) ist ein deutscher SPD-Politiker. ' & _
    'Er war von 1998 bis 2005 Bundeskanzler der Bundesrepublik Deutschland sowie zuvor von 1990 bis 1998 Ministerpräsident des Landes Niedersachsen. ' & _
    'Nach seiner politischen Karriere wechselte Schroeder in die Wirtschaft, wo er bis heute verschiedene Positionen bekleidet.' & _
    'Während und nach seiner Kanzlerschaft wurden und werden die Anhänger von Schröders Agenda 2010 auch „Schröderianer“ genannt.'

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

    $ret = _GetIntersection($txt1, $txt2, 0, ' ')
    $diff1 = ''
    $diff2 = ''
    If Not @error Then
    For $i = 0 To UBound($ret) -1
    If $ret[$i][1] <> '' Then $diff1 &= $ret[$i][1] & ' ; '
    If $ret[$i][2] <> '' Then $diff2 &= $ret[$i][2] & ' ; '
    Next
    EndIf
    MsgBox(0, '', 'Unterschiede 1: ' & $diff1 & @LF & 'Unterschiede 2: ' & $diff2)

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

    ;==================================================================================================
    ; Function Name: _GetIntersection($Set1, $Set2 [, $GetAll=0 [, $Delim=Default]])
    ; Description:: Detect from 2 sets
    ; - Intersection (elements are contains in both sets)
    ; - Difference 1 (elements are contains only in $Set1)
    ; - Difference 2 (elements are contains only in $Set2)
    ; Parameter(s): $Set1 set 1 (1D-array or delimited string)
    ; $Set2 set 2 (1D-array or delimited string)
    ; optional: $GetAll 0 - only one occurence of every different element are shown (Default)
    ; 1 - all elements of differences are shown
    ; optional: $Delim Delimiter for strings (Default use the separator character set by Opt("GUIDataSeparatorChar") )
    ; Return Value(s): Succes 2D-array [i][0]=Intersection
    ; [i][1]=Difference 1
    ; [i][2]=Difference 2
    ; Failure -1 @error set, that was given as array, is'nt 1D-array
    ; Note: Comparison is case-sensitiv! - i.e. Number 9 is different to string '9'!
    ; Author(s): BugFix ([email='bugfix@autoit.de'][/email])
    ;==================================================================================================
    Func _GetIntersection(ByRef $Set1, ByRef $Set2, $GetAll=0, $Delim=Default)
    Local $o1 = ObjCreate("System.Collections.ArrayList")
    Local $o2 = ObjCreate("System.Collections.ArrayList")
    Local $oUnion = ObjCreate("System.Collections.ArrayList")
    Local $oDiff1 = ObjCreate("System.Collections.ArrayList")
    Local $oDiff2 = ObjCreate("System.Collections.ArrayList")
    Local $tmp, $i
    If $GetAll <> 1 Then $GetAll = 0
    If $Delim = Default Then $Delim = Opt("GUIDataSeparatorChar")
    If Not IsArray($Set1) Then
    If Not StringInStr($Set1, $Delim) Then
    $o1.Add($Set1)
    Else
    $tmp = StringSplit($Set1, $Delim)
    For $i = 1 To UBound($tmp) -1
    $o1.Add($tmp[$i])
    Next
    EndIf
    Else
    If UBound($Set1, 0) > 1 Then Return SetError(1,0,-1)
    For $i = 0 To UBound($Set1) -1
    $o1.Add($Set1[$i])
    Next
    EndIf
    If Not IsArray($Set2) Then
    If Not StringInStr($Set2, $Delim) Then
    $o2.Add($Set2)
    Else
    $tmp = StringSplit($Set2, $Delim)
    For $i = 1 To UBound($tmp) -1
    $o2.Add($tmp[$i])
    Next
    EndIf
    Else
    If UBound($Set2, 0) > 1 Then Return SetError(1,0,-1)
    For $i = 0 To UBound($Set2) -1
    $o2.Add($Set2[$i])
    Next
    EndIf
    For $tmp In $o1
    If $o2.Contains($tmp) And Not $oUnion.Contains($tmp) Then $oUnion.Add($tmp)
    Next
    For $tmp In $o2
    If $o1.Contains($tmp) And Not $oUnion.Contains($tmp) Then $oUnion.Add($tmp)
    Next
    For $tmp In $o1
    If $GetAll Then
    If Not $oUnion.Contains($tmp) Then $oDiff1.Add($tmp)
    Else
    If Not $oUnion.Contains($tmp) And Not $oDiff1.Contains($tmp) Then $oDiff1.Add($tmp)
    EndIf
    Next
    For $tmp In $o2
    If $GetAll Then
    If Not $oUnion.Contains($tmp) Then $oDiff2.Add($tmp)
    Else
    If Not $oUnion.Contains($tmp) And Not $oDiff2.Contains($tmp) Then $oDiff2.Add($tmp)
    EndIf
    Next
    Local $UBound[3] = [$oDiff1.Count,$oDiff2.Count,$oUnion.Count], $max = 1
    For $i = 0 To UBound($UBound) -1
    If $UBound[$i] > $max Then $max = $UBound[$i]
    Next
    Local $aOut[$max][3]
    If $oUnion.Count > 0 Then
    $i = 0
    For $tmp In $oUnion
    $aOut[$i][0] = $tmp
    $i += 1
    Next
    EndIf
    If $oDiff1.Count > 0 Then
    $i = 0
    For $tmp In $oDiff1
    $aOut[$i][1] = $tmp
    $i += 1
    Next
    EndIf
    If $oDiff2.Count > 0 Then
    $i = 0
    For $tmp In $oDiff2
    $aOut[$i][2] = $tmp
    $i += 1
    Next
    EndIf
    Return $aOut
    EndFunc ;==>_GetIntersection

    [/autoit]
  • Perfekt, genau das was ich gerade gesucht habe :).

    Andy hat mir ein Schnitzel gebacken aber da war ein Raupi drauf und bevor Oscar das Bugfixen konnte kam Alina und gab mir ein AspirinJunkie.

  • Also ich habe das Script mit angeschaut und bin begeistert.
    Ein kleiner Punkt, den ich aber nicht als Fehler darstellen möchte ist, das wenn die Anzahl der aufeinander folgenden Leerzeichen größer gleich zwei ist, dieses nicht erkannt wurde. Oder ich bin zu blond gewesen beim testen. Aber suuuuuuper finde ich das Script auf jeden Fall. LOOOOOB !

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl