Häufigkeit der Wörter in einem Array

  • Hallo zusammen,

    ich habe folgendes Szenario gegeben:

    Code
    Name1 Datum
    Name2 Datum
    Name3 Datum
    Name2 Datum
    Name3 Datum
    Name4 Datum
    Name2 Datum

    Kurz gefasst: Es sollen alle row's geprüft werden und einzig (!) der Name ausgegeben werden, welcher am Häufigsten in diesen row's vorkommt. In diesem Beispiel würde ich also eine Variable mit dem Wert "Name2" erwarten. Das Datum ist irrelevant, es dient nur dafür, zu zeigen, dass es ein zweidimensionales Array ist.

    Das Array heißt übrigens $aExport.

    Ich danke vorab für alle Antworten und sende LG,

    der Robert :thumbup:

    Einmal editiert, zuletzt von DasIch (6. November 2014 um 16:12)

  • Du erstellst ein neues array mit 2 dimensionen. In der ersten spalte speicherst du alle vorkommenden namen ab, in der zweiten wie oft sie vorkommen. Du musst lediglich beide arrays durchlaufen und immer wieder vergleichen ob der name schon im neu angelegten array enthalten ist. Ist er das, dann den zähler um eins erhöhen, ist er es nicht fügst du den namen einfach noch hinzu. Den rest schaffst du denke ich alleine.

    Gesendet von meinem HTC Desire HD A9191 mit Tapatalk 2

  • @DasIch,
    wir vermissen dein Script, in dem du deinen Versuch zur Lösung deines Problems beschreibst!
    Oder soll dir hier jemand das Script fix und fertig vorlegen?

    Btw. gibt es die Funktion _ArrayUnique(), welche 99% deines Problems löst, einige Zeilen umschreiben/ergänzen und das wars...

  • Hallo zusammen,

    _ArrayUnique() habe ich versucht, aber leider werde ich daraus nicht wirklich schlau und es funktioniert nicht.. Dann habe ich versucht, die erste col des arrays in einen string umzuwandeln und diesen dann zu durchsuchen, auch hier hab ich keine lösung gefunden, wie das gehen soll..

    Spoiler anzeigen
    [autoit]

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

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

    Global $oAppl = _Excel_Open(False)

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

    Global $bCount = False
    Global $aNameOld = _FileListToArray(@ScriptDir, '*.xlsx', 1)
    _ArraySort($aNameOld, 0, 1)
    Global $aNameShort = $aNameOld
    Global $sInhalt = ""

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

    For $i = 1 To UBound($aNameOld) - 1
    $sInhalt = ""
    $aNameShort[$i] = StringTrimRight($aNameShort[$i], 5) ;wird später benötigt in den FF-Funktionen, um nach dem Dateinamen zu suchen
    Global $oWorkbook = _Excel_BookOpen($oAppl, @ScriptDir & "\" & $aNameOld[$i], False, False)
    Global $aInhalt = _Excel_RangeRead($oWorkbook, 1, "1:10")
    _Excel_BookClose($oWorkbook, False)

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

    _ArrayDisplay($aInhalt, 2)
    For $k = UBound($aInhalt) - 1 To 0 Step -1
    If $k = 0 Then
    MsgBox(48, "Fehler", "Fehler!")
    ExitLoop
    EndIf
    If $aInhalt[$k][0] = "" Then
    ReDim $aInhalt[$k][UBound($aInhalt, 2)]
    Else
    ExitLoop
    EndIf
    Next ;>> Kürzen des Arrays, um leere Zeilen zu entfernen

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

    For $l = 1 To UBound($aInhalt) - 1
    $sInhalt = $sInhalt & $aInhalt[$l][0] & "|"
    Next ;>> Array in einen String umwandeln

    ;~ $aUnique = _ArrayUnique($aInhalt, 0, 0, 0, 1) ;Kläglicher Versuch mit ArrayUnique..
    _ArrayDisplay($aInhalt)
    MsgBox(0, "", $sInhalt)
    $bCount = False
    ;~ MsgBox(0, "", "Username: " & $aInhalt[1][0])
    Next

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

    _Excel_Close($oAppl)

    [/autoit]

    2 Mal editiert, zuletzt von DasIch (6. November 2014 um 08:08)

  • Es sollen alle row's geprüft werden und einzig (!) der Name ausgegeben werden, welcher am Häufigsten in diesen row's vorkommt.

    Manchmal benötigt man nur den richtigen Suchbegriff.
    In deinem Fall dieser "Modalwert".
    Damit die Forensuche füttern und du findest Lösungen.
    Diese sind für 1D-Arrays aber, da dich eh nur eine bestimmte Spalte interessiert kannst du die Skripte ganz leicht entsprechend anpassen.

  • Das habe ich versucht, mit Hilfe der Datei von Bugfix, aber daraus werde ich nicht schlau...

    Spoiler anzeigen
    [autoit]


    $aIntersec = _GetIntersection($sInhalt, $sInhalt, 0, "|")
    _ArrayDisplay($aIntersec )
    MsgBox(0, "", $aIntersec [1][1])

    [/autoit]

    Damit bringt er zwar jeden wert nur einmal, aber welcher davon am meisten vertreten ist, das ist hieraus nicht ersichtlich.

  • Keine Ahnung wie du jetzt auf diese Funktion gekommen bist mit dem Suchbegriff "Modalwert".
    Hier halt vorgekaut (einzig die Anpassung auf ein 2D-Array musst du noch selbst übernehmen):

    Modalwert eines Arrays
    [autoit]

    #include <Array.au3>

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

    Global $a_Array[] = ["Name1", "Name2", "Name3", "Name2", "Name3", "Name4", "Name2"]

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

    Global $a_Max = _ArrayModalwert($a_Array, 1)
    _ArrayDisplay($a_Max, "Elemente mit maximalen Vorkommen")

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

    ; #FUNCTION# ======================================================================================
    ; Name ..........: _ArrayModalwert()
    ; Description ...: Bestimmt den Modalwert in einem Array
    ; Syntax ........: _ArrayModalwert(ByRef $a_Inp, Const[ $i_Start = 0, Const[ $s_Delim = "|"]])
    ; Parameters ....: ByRef $a_Inp - 1D-Array mit Stichprobenmenge
    ; Const $i_Start - [optional] Start Array-Index; gewöhnlich auf 0 oder 1 gesetzt (Standard = 0) (default:0)
    ; Const $s_Delim - [optional] Wenn "|" in den einzelnen Elementen vorkommt: ändern (default:"|")
    ; Return values .: Success: Array[0]: Anzahl an Vorkommen, Array[1..n]: häufigst vorgekommene Elemente
    ; Failure: Return 0 und setzt @error
    ; =================================================================================================
    Func _ArrayModalwert(ByRef $a_Inp, Const $i_Start = 0, Const $s_Delim = "|")
    Local $o_Dict = ObjCreate("Scripting.Dictionary")
    Local $i_CMax = 1, $i_C, $s_Mods
    ; Array durchgehen und Vorkommen von Werten zählen:
    If Not IsArray($a_Inp) Then Return SetError(1, 0, 0)
    For $x = $i_Start To UBound($a_Inp) - 1
    $o_Dict($a_Inp[$x]) += 1
    Next
    ; Werte mit maximalen Vorkommen ermitteln:
    For $i In $o_Dict.Keys
    $i_C = $o_Dict($i)
    If $i_C = $i_CMax Then
    $s_Mods &= $i & $s_Delim
    ElseIf $i_C > $i_CMax Then
    $i_CMax = $i_C
    $s_Mods = $i & $s_Delim
    EndIf
    Next
    Local $a_Return = StringSplit(StringTrimRight($s_Mods, 1), $s_Delim)
    $a_Return[0] = $i_CMax
    Return $a_Return
    EndFunc ;==>_ArrayModalwert

    [/autoit]
  • Ich denke für dein Vorhaben gibt es sehr viele Möglichkeiten und Lösungen. Da muss man Prinzip nur Wissen wie man googlet :whistling:

    Hierfür habe ich jedoch meine eigene Funktion geschrieben, basierend auf Strings und RegEx.
    Das was du noch selber machen musst, ist den höhsten Wert der Array ermitteln.

    Spoiler anzeigen
    [autoit]


    include <Array.au3>

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

    Local $aData[] = ['Name1','Name1','Name2','Name3','Name4','Name2','Name4','Name5','Name2','Name2']
    _arrayCompare_1D_to_2d($aData)
    _ArrayDisplay($aData)

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

    ;----------------------------------------------------------------------------------------------/
    ; Beschreibung: = Ermittelt aus einem 1D Array die Anzahl aller gleichen Vorkommen und übergibt
    ; ein 2D Array
    ; Parameter: = 1D - Array
    ; @return: = 2D - Array
    ; Include = <Array.au3>
    ;
    ; Update = 06.11.2014
    ; von = 4ern.de
    ;----------------------------------------------------------------------------------------------/
    func _arrayCompare_1D_to_2d(byref $aData)

    Local $aData_new[UBound($aData)][2] ;Neues 2D Array erstellen
    Local $s_Data = _ArrayToString($aData, '|') ;Ursprungs Array in ein String setzen

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

    ;----------------------------------------------------------------------------------------------/
    ; Schleife
    ; Durchlauf aller Elmente in einem Array
    ;----------------------------------------------------------------------------------------------/
    for $i = 0 to Ubound($aData) -1
    $a_regEX = StringRegExp($s_Data, $aData[$i],3) ;Setze alle Vorkommen in ein Array
    if @error then ContinueLoop
    $s_Data = StringReplace($s_Data, $aData[$i], '') ;Lösche Element aus dem String

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

    $aData_new[$i][0] = $a_regEX[0] ;setze den Ursprünglichen Wert in 2D
    $aData_new[$i][1] = ubound($a_regEX) ;Zähle Anzahl der Dopplungen und setze in 2D
    next

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

    ;Lösche alle Leeren Elemente
    for $i = Ubound($aData_new) -1 to 0 step -1
    if $aData_new[$i][0] = '' then _ArrayDelete($aData_new, $i)
    next

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

    $aData = $aData_new
    return $aData
    endfunc ;<==/

    [/autoit]
  • Ich habe die Lösung von AspirinJunkie genommen, ein bisschen angepasst und siehe da: es läuft :D

    Danke euch allen für eure Hilfe!

    Hier noch der Code, wie es bei mir funktioniert hat:

    Spoiler anzeigen
    [autoit]


    Global $iInhalt = UBound($aInhalt)
    Global $aInhaltName[$iInhalt]
    Global $aInhaltIp[$iInhalt]
    For $l = 1 To UBound($aInhaltName) - 1
    $aInhaltName[$l] = $aInhalt[$l][1]
    $aInhaltIp[$l] = StringTrimLeft($aInhalt[$l][10], 6)
    $aInhaltIpSplit = StringSplit($aInhaltIp[$l], ".")
    $aInhaltIp[$l] = $aInhaltIpSplit[1] & "." & $aInhaltIpSplit[2] & "." & $aInhaltIpSplit[3] & ".0"
    Next
    $aInhaltName = _ArrayModalWert($aInhaltName, 1)

    [/autoit]