Zähle Vorkommen in Array

  • Hallo,

    folgendes Problem: Ich habe ein Array, in dem zig Werte gespeichert sind. Nun möchte ich von den beiden höchsten Vorkommenden Werten die Anzahl so wie ihren Wert wissen.
    Gibt es dafür irgendeine nette Such-/Count-Funktion, die ich noch nicht kenne oder muss ich mir den Aufwand machen und das ganze mühselig per Hand in 2 for-Schleifen abwickeln :p ?

    MfG,
    dschihejns

  • Ubound ist dein Freund ;)

    Spoiler anzeigen
    [autoit]

    Local $array[5] = [1, 2, 3, 4 , 5]

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

    $Anzahl_Werte = UBound($array)

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

    $vorletzter = $array[$Anzahl_Werte - 2]
    $letzter = $array[$Anzahl_Werte - 1]

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

    ConsoleWrite($vorletzter & @CR)
    ConsoleWrite($letzter & @CR)

    [/autoit]
  • Die Anzahl bekommst du so heraus
    bsp:

    Spoiler anzeigen
    [autoit]

    Dim $array[7]
    $array[0] = 6
    For $zahl = 1 To 6 Step +1
    $array[$zahl] = $zahl
    Next

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

    ReDim $array[13]
    $array[0] = 12
    For $nummer = 6 To 11 Step +1
    $array[$nummer + 1] = $nummer
    Next

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

    $iRet = _NumberingWordsInArray($array,1)
    MsgBox(0,"",$iRet)

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

    Func _NumberingWordsInArray($iArray,$iSearch)
    ;Author: simon(http://www.autoit.de)
    Local $i,$iNumber = 0
    If IsArray($iArray) And $iSearch <> "" Then
    For $i = 1 To $iArray[0]
    If $iArray[$i] = $iSearch Then
    $iNumber += 1
    Endif
    Next
    If Not @error Then
    return $iNumber
    else
    return -1
    Endif
    else
    return -2
    Endif
    EndFunc

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

    Das andere ist schwieriger du willst also in einem Array die beiden höchsten werte herausfinden ,oder?

  • Hi,
    also mal ins unreine gesprochen....

    $avArray ist dein Array mit den Werten

    Erst _Arraysort($avArray, 0, 0, 0, 0) ....
    dann den Wert $avArray[1] ....
    dann $avArray[UBound($avArray)] ...
    So und nun beide Werte jeweils mit _ArrayFindAll($avArray, $avArray[1]) und jetzt noch
    _ArrayFindAll($avArray, $avArray[UBound($avArray)])

    so sollte das aussehen.

    MfG
    Der_Doc

  • Ich habe mal noch was gemacht um die beiden höchsten herauszufinden
    bsp mit dem anderen:

    Spoiler anzeigen
    [autoit]

    Dim $array[7]
    $array[0] = 6
    For $zahl = 1 To 6 Step +1
    $array[$zahl] = $zahl
    Next

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

    ReDim $array[13]
    $array[0] = 12
    For $nummer = 6 To 11 Step +1
    $array[$nummer + 1] = $nummer
    Next

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

    $iRet = _NumberingWordsInArray($array,1)
    MsgBox(0,"",$iRet)

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

    $sRet = _Find2HightesNumbersInArray($array)
    MsgBox(0,"",$sRet[0] & " " & $sRet[1])

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

    Func _NumberingWordsInArray($iArray,$iSearch)
    ;Author: simon(http://www.autoit.de)
    Local $i,$iNumber = 0
    If IsArray($iArray) And $iSearch <> "" Then
    For $i = 1 To $iArray[0]
    If $iArray[$i] = $iSearch Then
    $iNumber += 1
    Endif
    Next
    If Not @error Then
    return $iNumber
    else
    return -1
    Endif
    else
    return -2
    Endif
    EndFunc

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

    Func _Find2HightesNumbersInArray($iArray)
    ;Author: simon(http://www.autoit.de)
    If IsArray($iArray) Then
    Local $iNumber1 = - 1,$iNumber2 = - 1
    For $i = 1 To $iArray[0]
    If $i <> $iArray[0] Then
    If $iArray[$i] > $iArray[$i + 1] Then
    If $iNumber1 < $iArray[$i] Then
    $iNumber2 = $iNumber1
    $iNumber1 = $iArray[$i]
    elseif $iNumber1 > $iArray[$i] Then
    If $iNumber2 < $iArray[$i] Then
    $iNumber2 = $iArray[$i]
    Endif
    Endif
    elseif $iArray[$i + 1] > $iArray[$i] Then
    If $iNumber1 < $iArray[$i + 1] Then
    $iNumber2 = $iNumber1
    $iNumber1 = $iArray[$i + 1]
    elseif $iNumber1 > $iArray[$i + 1] Then
    If $iNumber2 < $iArray[$i + 1] Then
    $iNumber2 = $iArray[$i + 1]
    Endif
    Endif
    Endif
    elseif $i = $iArray[0] Then
    If $iArray[$i] > $iNumber1 Then
    $iNumber2 = $iNumber1
    $iNumber1 = $iArray[$i]
    elseif $iArray[$i] < $iNumber1 Then
    $iNumber2 = $iArray[$i]
    Endif
    Endif
    Next
    Dim $return[2]
    $return[0] = $iNumber1
    $return[1] = $iNumber2
    If Not @error Then
    If $return[0] <> -1 Then
    If $return[1] <> -1 Then
    return $return
    else
    return $iNumber1
    Endif
    else
    return -1
    Endif
    else
    return -2
    Endif
    else
    return -3
    Endif
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit]
    • Offizieller Beitrag

    Naja mal ein Beispiel:

    [autoit]

    #include <Array.au3>
    Dim $aTest[1000]
    For $i = 0 To 999
    $aTest[$i] = Random(1, 300, 1)
    Next
    $Temp = $aTest
    _ArraySort($Temp)
    _ArrayDisplay($Temp)
    $iMax = _ArrayMax($Temp); Größte Zahl im Array
    $aMaxIdx = _ArrayFindAll($Temp, $iMax);Alle Vorkommen finden
    $iMaxCount = UBound($aMaxIdx);Anzahl der Größten Zahl im Array
    For $i = UBound($aMaxIdx) - 1 To 0 Step -1;Alle Vorkommen aus dem TempArray löschen
    _ArrayDelete($Temp, $aMaxIdx[$i])
    Next
    $iMax2 = _ArrayMax($Temp);Größte Zahl im Array
    $aMaxIdx2 = _ArrayFindAll($Temp, $iMax2);Alle Vorkommen finden
    $iMaxCount2 = UBound($aMaxIdx2);Anzahl der Größten Zahl im Array
    MsgBox(0, "Info", "Größte Zahl : " & $iMax & " Anzahl : " & $iMaxCount & @CRLF & _
    "Zweitgrößte Zahl: " & $iMax2 & " Anzahl : " & $iMaxCount2)

    [/autoit]


    Edit: Habe extra das Array in die Variable $Temp umkopiert, damit das Ursprungsarray nicht zerstört wird.
    Kommentare eingefügt.
    @simon, einen längeren Code hast du nicht? :pinch:

    • Offizieller Beitrag

    Wenn die Funktion auch das richtige Ergebnis liefern würde, wäre das ein Argument.
    Ist aber nicht so.

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    #cs **************************************************************************

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

    Zähle Vorkommen in Array

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

    http://www.autoit.de/index.php?page…7885#post117885

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

    #ce **************************************************************************
    Dim $array[1001]
    For $i = 1 To 1000
    $array[$i] = Random(1, 300, 1)
    Next
    $array[0] = 1000
    ;Dieser Teil dient nur zur Überprüfung
    $Tmp = $array
    _ArrayDelete($Tmp,0)
    _ArraySort($Tmp,1)
    _ArrayDisplay($Tmp)
    ;Ende Überprüfung
    $iRet = _NumberingWordsInArray($array,300)
    MsgBox(0,"",$iRet)

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

    $sRet = _Find2HightesNumbersInArray($array)
    MsgBox(0,"",$sRet[0] & " " & $sRet[1])

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

    Func _NumberingWordsInArray($iArray,$iSearch)
    ;Author: simon(http://www.autoit.de)
    Local $i,$iNumber = 0
    If IsArray($iArray) And $iSearch <> "" Then
    For $i = 1 To $iArray[0]
    If $iArray[$i] = $iSearch Then
    $iNumber += 1
    Endif
    Next
    If Not @error Then
    return $iNumber
    else
    return -1
    Endif
    else
    return -2
    Endif
    EndFunc

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

    Func _Find2HightesNumbersInArray($iArray)
    ;Author: simon(http://www.autoit.de)
    If IsArray($iArray) Then
    Local $iNumber1 = - 1,$iNumber2 = - 1
    For $i = 1 To $iArray[0]
    If $i <> $iArray[0] Then
    If $iArray[$i] > $iArray[$i + 1] Then
    If $iNumber1 < $iArray[$i] Then
    $iNumber2 = $iNumber1
    $iNumber1 = $iArray[$i]
    elseif $iNumber1 > $iArray[$i] Then
    If $iNumber2 < $iArray[$i] Then
    $iNumber2 = $iArray[$i]
    Endif
    Endif
    elseif $iArray[$i + 1] > $iArray[$i] Then
    If $iNumber1 < $iArray[$i + 1] Then
    $iNumber2 = $iNumber1
    $iNumber1 = $iArray[$i + 1]
    elseif $iNumber1 > $iArray[$i + 1] Then
    If $iNumber2 < $iArray[$i + 1] Then
    $iNumber2 = $iArray[$i + 1]
    Endif
    Endif
    Endif
    elseif $i = $iArray[0] Then
    If $iArray[$i] > $iNumber1 Then
    $iNumber2 = $iNumber1
    $iNumber1 = $iArray[$i]
    elseif $iArray[$i] < $iNumber1 Then
    $iNumber2 = $iArray[$i]
    Endif
    Endif
    Next
    Dim $return[2]
    $return[0] = $iNumber1
    $return[1] = $iNumber2
    If Not @error Then
    If $return[0] <> -1 Then
    If $return[1] <> -1 Then
    return $return
    else
    return $iNumber1
    Endif
    else
    return -1
    Endif
    else
    return -2
    Endif
    else
    return -3
    Endif
    EndFunc

    [/autoit]

    Sobald Werte mehrfach vorkommen, klappt es nicht.

  • Hallo Raupi ,

    es geht auch ohne _ArrayDelete, dadurch etwas kürzer und minimaal schneller:

    Spoiler anzeigen
    [autoit]

    #include <array.au3>
    Dim $array[10000]
    dim $max[2][2]
    $array[0] = 9999
    For $i = 1 To 9999
    $array[$i] = Random(1,999,1)
    Next
    _ArraySort($array,0,1,9999)
    _ArrayDisplay($array,"Jetzt befindet sich die höchste Zahl am Ende BITTE Zur Kontrolle kopieren!!!!")
    $max[0][0] = $array[$array[0]] ;die absolute größte Zahl
    $max[0][1] = _ArrayFindAll($array,$max[0][0],1,9999) ;ein Array mit ALLEN gefundenen Werten der größten Zahl!!!!!!!
    $max[1][0] = $array[$array[0] - UBound($max[0][1])] ;die 2 größte Zahl
    $max[1][1] = _ArrayFindAll($array,$max[1][0],1,9999) ;ein Array mit ALLEN gefundenen größten Werten der 2. Zahl!!!!!!!
    ConsoleWrite($max[0][0] & " ist " & UBound($max[0][1]) & " mal im Array vorhanden" & @crlf)
    ConsoleWrite($max[1][0] & " ist " & UBound($max[1][1]) & " mal im Array vorhanden" & @crlf)

    [/autoit]

    mfg (Auto)Bert

    • Offizieller Beitrag

    Auch Schön :thumbup:
    Welche unserer Lösungen schneller ist kann ich eigentlich nicht sagen. Hab das jetzt zig mal getestet. Entweder gewinnt deine oder meine :pinch:

    Spoiler anzeigen
    [autoit]

    #include <array.au3>

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

    Dim $array[10000]
    Dim $max[2][2]
    $array[0] = 9999
    For $i = 1 To 9999
    $array[$i] = Random(1, 999, 1)
    Next
    $Temp = $array

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

    $timer1 = TimerInit()
    _ArraySort($array, 0, 1, 9999)
    $max[0][0] = $array[$array[0]] ;die absolute größte Zahl
    $max[0][1] = _ArrayFindAll($array, $max[0][0], 1, 9999) ;ein Array mit ALLEN gefundenen Werten der größten Zahl!!!!!!!
    $max[1][0] = $array[$array[0] - UBound($max[0][1])] ;die 2 größte Zahl
    $max[1][1] = _ArrayFindAll($array, $max[1][0], 1, 9999) ;ein Array mit ALLEN gefundenen größten Werten der 2. Zahl!!!!!!!
    ConsoleWrite($max[0][0] & " ist " & UBound($max[0][1]) & " mal im Array vorhanden" & @CRLF)
    ConsoleWrite($max[1][0] & " ist " & UBound($max[1][1]) & " mal im Array vorhanden" & @CRLF)
    $timer1 = TimerDiff($timer1)

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

    $Timer = TimerInit()
    _ArrayDelete($Temp, 0)
    _ArraySort($Temp)
    $iMax = _ArrayMax($Temp); Größte Zahl im Array
    $aMaxIdx = _ArrayFindAll($Temp, $iMax, 1, 9999);Alle Vorkommen finden
    $iMaxCount = UBound($aMaxIdx);Anzahl der Größten Zahl im Array
    For $i = UBound($aMaxIdx) - 1 To 0 Step -1;Alle Vorkommen aus dem TempArray löschen
    _ArrayDelete($Temp, $aMaxIdx[$i])
    Next
    $iMax2 = _ArrayMax($Temp);Größte Zahl im Array
    $aMaxIdx2 = _ArrayFindAll($Temp, $iMax2);Alle Vorkommen finden
    $iMaxCount2 = UBound($aMaxIdx2);Anzahl der Größten Zahl im Array
    ConsoleWrite("Größte Zahl : " & $iMax & " Anzahl : " & $iMaxCount & @CRLF & _
    "Zweitgrößte Zahl: " & $iMax2 & " Anzahl : " & $iMaxCount2 & @CRLF)
    $Timer = TimerDiff($Timer)

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

    MsgBox(0, "", "Zeitmessung AutoBert: " & $timer1 & @CRLF & "Zeitmessung Raupi: " & $Timer)

    [/autoit]


    Da kommen teilweise alsolut komische Werte raus. Kannst ja mal austesten. :thumbup: Zumindest ist deine Lösung kürzer.

    Edit: Deine Lösung ist scheinbar 1/3 Schneller, klarer Sieger. :thumbup:

  • Hallo Raupi,

    da die Routinen ja bis auf den Teil in dem du die gefundenen Werte der größten Zahl löschst identisch sind, ist der Unterschied zwangsläufig die Zeiz die fürs Löschen benötigt wird. Aber diese 0,4 -0,6 Sekunden dürften wohl nicht stören,

    mfg (Auto)Bert

    • Offizieller Beitrag

    @dschihejns ,ich denke das ist doch gut kommentiert. Du schafst das schon. Wenn nicht frag einfach.

    autoBert, ich denke das liegt am ReDim in _ArrayDelete. ReDim ist grottenlahm.