Durchschnitt errechnen

  • Es wird für manche einfach sein aber ich komme hier nicht weiter... Ich hoffe ihr könnt mir helfen.

    Ich habe eine txt-Datei mit folgender Aufbau:

    Code
    25,111	56
    5,192	56
    99,713	34
    7,111	45
    12,449	56
    80,152	45
    30,216	34
    57,568	34
    60,993	45
    46,094	56


    Der inhalt der Datei ist vorher nicht bekannt. Wie berechne ich der Durchschnitt von die Zahlen in der ersten Spalte per Kategorie in der Zweiten Spalte? Also der Durchschnitt aller zahlen in der ersten Spalte wenn in der zweiten 56 steht, der Durchschnitt wenn in der zweiten 34 steht und so weiter.

    Programmieren ist ein bisschen Wissenschaft und viel Spass! :)

  • Auf die Schnelle:
    Datei in einen 2D-Array einlesen und nach der zweiten Spalte sortieren.
    Dann durch den Array loopen, Elemente der Spalte 1 summieren und Anzahl zählen. Jeweils bei Wechsel des Wertes in Spalte 2 den Durchschnitt berechnen.

  • Nicht die optimalste Lösung, aber sie funktioniert... :D

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

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

    Local $Array = _GetAverage(@ScriptDir & "\data.txt")

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

    For $i = 1 To $Array[0] Step +2
    ConsoleWrite($Array[$i] & " = " & $Array[$i + 1] & @LF)
    Next

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

    Func _GetAverage($sFile)
    Local $aReturn[1], $aItems, $aCollums, $aFind, $iAll = 0, $sData = FileRead($sFile)
    If StringRight($sData, 1) <> @CRLF Then $sData &= @CRLF
    $aItems = StringRegExp($sData, "(\d+,\d+)\s\d+\s", 3)
    $aCollums = StringRegExp($sData, "\d+,\d+\s(\d+)\s", 3)
    Do
    $aReturn[0] += 2
    _ArrayAdd($aReturn, $aCollums[0])
    $aFind = _ArrayFindAll($aCollums, $aCollums[0])
    $iAll = 0
    For $i = 0 To UBound($aFind) - 1
    $iAll += Number(StringReplace($aItems[$aFind[$i]],",","."),3)
    Next
    For $y = 0 To UBound($aFind) - 1
    _ArrayDelete($aCollums, $aFind[$y] - $y)
    _ArrayDelete($aItems, $aFind[$y] - $y)
    Next
    _ArrayAdd($aReturn, $iAll / UBound($aFind))
    Until UBound($aCollums) = 0
    Return $aReturn
    EndFunc ;==>_GetAverage

    [/autoit]

    Edit: Fehler verbessert!

    LG
    Christoph :)

    Einmal editiert, zuletzt von BinDannMalWeg (25. November 2012 um 20:01)

  • Und noch ein Lösungsvorschlag:

    Spoiler anzeigen
    [autoit]

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

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

    Global $aFile, $sSep = @TAB ;Trenner evtl. anpassen

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

    _FileReadToArray(@ScriptDir & "\2dAverage.txt", $aFile)
    ;_ArrayDisplay($aFile)
    Global $a2D[$aFile[0]][2]
    _ArrayDelete($aFile, 0)
    For $i = 0 To UBound($aFile) - 1
    $aSplit = StringSplit($aFile[$i], $sSep, 2)
    $a2D[$i][0] = $aSplit[1]
    $a2D[$i][1] = StringReplace($aSplit[0],",",".")
    Next

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

    ;Summierung
    $aRes = _ArrayAverage2D($a2D)
    _ArrayDisplay($aRes, "Durchschnitt")

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

    Func _ArrayAverage2D(ByRef $avArray)
    Local $sActCol, $iActCol = -1, $sRes, $iRes
    Local $aTmp = _ArrayUnique($avArray)
    _ArrayDelete($aTmp, 0)
    _ArraySort($aTmp)
    Local $aRes[4][UBound($aTmp)+1]
    For $i = 0 To UBound($aTmp) -1
    $aRes[0][$i+1] = $aTmp[$i]
    Next
    $aRes[0][0] = "Nr"
    $aRes[1][0] = "Summe"
    $aRes[2][0] = "Anzahl"
    $aRes[3][0] = "Durchschnitt"
    For $i = 0 To UBound($avArray) - 1
    For $j = 0 To UBound($aRes,2)-1
    ConsoleWrite($avArray[$i][0]&@TAB&$avArray[$i][1]&@CRLF)
    If $aRes[0][$j] = $avArray[$i][0] Then
    $aRes[1][$j] += $avArray[$i][1]
    $aRes[2][$j] += 1
    EndIf
    Next
    Next
    For $j = 1 To UBound($aRes,2)-1
    $aRes[3][$j] = $aRes[1][$j] / $aRes[2][$j];evtl. noch runden
    Next
    Return $aRes
    EndFunc ;==>_ArrayAverage2D

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

    Edit: einer von uns beiden hat die Aufgabenstellung nicht richtig erfasst,ich komme auf ein ganz anderes Eregebnis.

    mfg autoBert

  • Ja ich hatte da echt was falsch verstanden, habe meinen Post oben verbessert...


    Jetzt sind die Ergebnisse identisch bei der Laufzeit benötigt mein Skript 4.99809243912285 ms deines 7.65493295935657 ms (jeweils Durchschnitt aus 10.000 Durchläufen).

    mfg autoBert

  • Warum die Textdatei nicht mittels ADO einlesen und auswerten?

    Spoiler anzeigen
    [autoit]


    AutoItSetOption('MustDeclareVars', 1)

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

    ; Konstanten bitte anpassen
    Const $DIRECTORY = 'C:\Dokumente und Einstellungen\Administrator\Desktop\cvsexample\'
    Const $TEXT_FILE = 'daten.txt'
    ; ---

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

    Const $REGKEY_PATH = 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Text'
    Dim $Buffer = ''

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

    If StringLower(RegRead($REGKEY_PATH, 'Format')) <> 'tabdelimited' Then
    $Buffer = RegRead($REGKEY_PATH, 'Format')
    RegWrite($REGKEY_PATH, 'Format', 'REG_SZ', 'TabDelimited')
    EndIf

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

    Dim $con = ObjCreate('ADODB.Connection')
    Dim $rs = ObjCreate('ADODB.RecordSet')

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

    $con.Provider = 'Microsoft.Jet.OLEDB.4.0'
    $con.ConnectionString = StringFormat( _
    'Data Source="%s";' & _
    'Extended Properties="text;HDR=NO";', _
    $DIRECTORY)
    $con.Open

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

    $rs.Open(StringFormat( _
    'SELECT F2, SUM(F1), COUNT(F2), AVG(F1) ' & _
    'FROM %s ' & _
    'GROUP BY F2', $TEXT_FILE), $con)

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

    ConsoleWrite(StringFormat('%-10s%-10s%-10s%s\n', 'Wert', 'Summe', 'Anzahl', 'Durschnitt'))
    While Not $rs.EOF
    ConsoleWrite(StringFormat('%-10s%-10s%-10s%s\n', _
    $rs.Fields(0).Value, $rs.Fields(1).Value, $rs.Fields(2).Value, $rs.Fields(3).Value))
    $rs.MoveNext()
    WEnd

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

    $rs.Close()
    $con.Close()

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

    If $Buffer <> '' Then
    RegWrite($REGKEY_PATH, 'Format', 'REG_SZ', $Buffer)
    EndIf

    [/autoit]
  • Ich habe bisher noch nie gesehen dass jemand den Median als "Durchschnitt" bezeichnet.
    Daher denke ich kann man davon ausgehen das hier der arithmetische Mittelwert gemeint ist.

    Btw: Mein Vorschlag:

    Spoiler anzeigen
    [autoit]

    Global Const $s_FilePath = "Test.txt"

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

    Global $dic_Sums = ObjCreate("Scripting.Dictionary"), $dic_Ns = ObjCreate("Scripting.Dictionary") ; Ein Dictionary für die Summen, eins für die Anzahl an Werten
    Global $a_Split

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

    Global $h_File = FileOpen($s_FilePath)
    If $h_File = -1 Then Exit MsgBox(0, "Fehler", "Die Datei konnte nicht geöffnet werden.")

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

    Do
    $s_Line = FileReadLine($h_File)
    If @error = -1 Then ExitLoop
    $a_Split = StringSplit(StringReplace($s_Line, ',', '.'), @TAB, 2)

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

    $dic_Ns($a_Split[1]) = $dic_Ns($a_Split[1]) + 1
    $dic_Sums($a_Split[1]) = $dic_Sums($a_Split[1]) + $a_Split[0]
    Until 0
    FileClose($h_File)

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

    For $i In $dic_Sums.Keys
    ConsoleWrite(StringFormat("Zahl:\t\t%-4d\nAnzahl:\t\t%-3d\nSumme:\t\t%-9.3f\nMittelwert:\t%-9.3f\n\n", $i, $dic_Ns($i), $dic_Sums($i), $dic_Sums($i) / $dic_Ns($i)))
    Next

    [/autoit]