Text nach Zeilen sortieren.

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
codingnoob
User
Beiträge: 4
Registriert: Sonntag 12. März 2017, 16:35

An erster Stelle erstmal: Ich bin Anfänger.
Wo das jetzt geklärt wäre; ich möchte aus einem Textdokument die Linien (Bsp.: 1.09.12,1.01.22,2.07.12,2.19.16) Abhängig von der ersten Nummer (1-5) und jede Zeile ist durch ein"," getrennt.
Außerdem soll dann in Unterkategorien noch nach der 2. Zahl (nach dem ersten Punkt) sortiert werden, und dann von diesen Unterkategorien der Durchschnitt der letzten Nummer ausgegeben werden. So weit so kompliziert.
Ich weiß dass das mehrere Rechnungen erfordert, aber wäre froh über wenigstens einzelne Teile.
Auch habe ich gelesen, dass hier nicht der Sinn ist, andere für einen programmieren zu lassen und habe mich schon versucht zu belesen. Herausgekommen ist dann das folgende, was leider anscheinend auch nicht funktioniert.


Code: Alles auswählen

levelsort = open("/Users/Friedel/Desktop/voting/vote-1.txt", "r")
num = ('1', '2', '3', '4', '5')

def get_lines(line):
    lines = line.strip(1) 
    lines = line.split("=")
    for set in lines :
        if set.startswith(num):
            set = set.replace("_"," ")
            set = set[0:3] 
            return set

get_lines = sorted(levelsort, key=get_lines)

for line in get_lines:

    f = open("votingausw.txt","a") 
    f.write(line + "\n")


Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@codingnoob: Anfänger zu sein ist kein Problem. Das waren hier alle mal. Allerdings verstehe ich Deine Frage nicht so recht. Da müsste ich zum großen Teil raten, was Du genau meinst, bzw. wissen, wie die Inhalte Deiner Datei ausschauen. Geraten sieht leider auch Dein Code aus. Versuche doch erst einmal den Inhalt einer Datei einzulesen und wieder auszugeben, oder in eine andere Datei zu schreiben. Wenn das klappt, kannst Du Dich Deiner Aufgabe besser annähern.
Zuletzt geändert von kbr am Sonntag 12. März 2017, 17:37, insgesamt 1-mal geändert.
BlackJack

@codingnoob: Vorab: Das was Du „Linien“ nennst sind „Zeilen“. Und das was Du dann Zeilen nennst sind — keine Ahnung, so ganz schlau werde ich da nicht aus der Beschreibung. Auf jeden Fall trennt man Zeilen nicht durch Kommas. Es sei denn Zeile bedeutet noch etwas anderes als eine Zeile einer Textdatei. Das müsste man dann aber deutlich erklären und immer deutlich machen wann man eine Zeile und wann eine Zeile meint. Oder eben nicht beides Zeile nennen. :-)

Also nach was willst Du denn nun sortieren? Nach Zeilen oder nach Zeilen, und wonach dann eigentlich? Beschreib doch mal etwas mehr was Du hast und was Du haben willst, mit Beispielen für beides. Vielleicht wird dann das zu lösende Problem klarer.

Der Name `get_lines` wird im Programm für zwei sehr unterschiedliche Sachen verwendet. Für eine Funktion und für eine Liste. Nur für die Funktion macht der Name an sich Sinn, weil er eine Tätigkeit beschreibt. Die Tätigkeit die er beschreibt, ist aber verwirrend, nämlich aus einer übergebenen Zeile die Zeilen extrahieren macht keinen Sinn. Zudem wird gleich die erste Zeile in dieser Funktion zu einer Ausnahme führen, denn die `strip()`-Methode kann nichts mit Zahlen als Argumenten anfangen.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@codingnoob:
`sorted` direkt auf ein Dateiobjekt anzuwenden, hab ich noch nicht gesehen, sollte aber prinzipiell funktionieren. Sei aber gewarnt, dass dieses Vorgehen sehr speicherhungrig für große Dateien wird.
Da Deine "Zeilen" nicht per NL sondern Komma getrennt sind, geht es so allerdings nicht, da der Zeileniterator nicht über Deine "Zeilen" trennt sondern alles im ersten Treffer ausliefert.
Was Du da mit `for set in lines :` machst, versteh ich nicht. Wenn die Zeilen mit `x.y.z` beginnen und x, y, z Zahlenliterale sind, kannst Du die Ordnung einfach über deren Zahlenwerte aufbauen, in dem Du eine Liste der Integerwerte zurückgibst in der key-Funktion, z.B. map(int, [x, y, z]). An die Stringliterale für x, y, z kommst Du per `split` oder Regexp ran.
Zuletzt geändert von jerch am Sonntag 12. März 2017, 17:49, insgesamt 1-mal geändert.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Irgendwie scheint dein Code nicht zum Beispiel zu passen. Es kommt kein = oder _ vor. Wie wäre es mit Mustern die tatsächlich zu deinem Problem passen...?

Gemäß den vorliegenden Daten kann man die Sortierung erreichen mittels:

Code: Alles auswählen

sorted(data.split(','))
Möglicherweise brauchst du das:

Code: Alles auswählen

def parse_data(s):
    parts = map(float, s.split('.'))
    return list(parts)

def main():
    s = '1.09.12,1.01.22,2.07.12,2.19.16'
    print(sorted(s.split(','), key=parse_data))

if __name__ == '__main__':
    main()
codingnoob
User
Beiträge: 4
Registriert: Sonntag 12. März 2017, 16:35

Die auszuwertende Datei sieht so aus:
1.02.25,
1.04.20,
1.03.15,
1.05.19,
1.09.12,
1.01.22,
2.07.12,
2.19.16,
2.06.29,

allerdings wird sie noch länger werden.
Die erste Zahl (Kategorie in was bewertet wird) gibt die oberkategorie an: (1-5)
die zweite Zahl welche Person) eine weitere Aufteilung (in den 5 von oben) (1-35)
und die dritte Zahl ist quasi die Bewertung (1-30)

falls das mit den Kommata ein Problem sein sollte, kann ich es in meiner App auch ändern.


Also der erste Schritt zu Lösung denke ich wäre, die Zeilen nach den ersten Nummern zu ordnen.
(Dann in dieser Ordnung (Seperate Dateien?) nach der 2 Zahl zu sortieren.)
(und am Schluss den Durchschnitt der letzten Zahl in der jeweiligen Kategorie)
Vielleicht wird mein Problem jetzt besser verstanden... ;)

und schön dass ihr so freundlich seid! erlebt man nicht überall so :)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Ungetestet:

Code: Alles auswählen

import re
def parse_nums(line):
    return map(int, re.match('(\d+)\.(\d+)\.(\d+).*', line).groups())
sorted(open('filename'), key=parse_nums)
Der Code setzt voraus, dass Deine Zeilen doch per newline und nicht nur per Komma getrennt sind. Danach sieht nämlich Dein Bsp. aus.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@codingnoob: wenn es nur auf den Mittelwert der Bewertungen einer Kategorie ankommt, könnte das folgende vielleicht Deiner gewünschten Lösung nahekommen:

Code: Alles auswählen

from collections import defaultdict

dd = defaultdict(list)

with open('deine_datei.txt') as fobj:
    for line in fobj:
        category, person, value = line.rstrip(',\n').split('.')
        dd[category].append(float(value))

for category in dd:
    values = dd[category]
    print(category, sum(values)/len(values))
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

Ich habe damit selbst bisher noch nie etwas gemacht, aber deine Beschreibung klingt ein bisschen so, als könnte vielleicht auch Pandas von Interesse sein. Es erinnert in der Handhabung recht stark an R (nur dass die Programmiersprache weniger seltsam ist ;) ).

Beispiel mit deinen Beispieldaten:

Code: Alles auswählen

In [1]: import pandas as pd

In [2]: import numpy as np

In [3]: table = pd.read_table('data.txt', sep='.', header=None)

In [4]: table[2] = table[2].str.strip(',').astype(np.int64)

In [5]: table.mean()
Out[5]: 
0     1.333333
1     6.222222
2    18.888889
dtype: float64

In [6]: table[2].groupby(table[0]).mean()
Out[6]: 
0
1    18.833333
2    19.000000
Name: 2, dtype: float64
codingnoob
User
Beiträge: 4
Registriert: Sonntag 12. März 2017, 16:35

@kbr dein code sieht ziemlich gut in meinen Augen aus. Allerdings bekomme ich eine Errormeldung und schaffe es seit einer halben Stunde nicht, den Grund zu finden, selbst wenn ich den split und/oder die TXT verändere.
Wird einer daraus schlau?

Code: Alles auswählen

from collections import defaultdict
 
dd = defaultdict(list)
 
with open('/Users/Friedel/Desktop/voting/vote-1.txt') as fobj:
    for line in fobj:
        category, person, value = line.rstrip(',\n').split('.')
        dd[category].append(float(value))
 
for category in dd:
    values = dd[category]
    print(category, sum(values)/len(values))

Ausgangsdatei:

1.02.25,
1.04.20,
1.03.15,
1.05.19,
1.09.12,
1.01.22,
2.07.12,
2.19.16,
2.06.29,


Error:

Traceback (most recent call last):
File "/Users/Friedel/Desktop/voting/votingausw.py", line 7, in <module>
category, person, value = line.rstrip(',\n').split('.')
ValueError: not enough values to unpack (expected 3, got 1)


Ich werde einfach nicht schlau draus.
Kann mir da vielleicht jemand helfen?


Wäre es außerdem möglich, die darauf folgende print-Ausgabe in ein anderes Dokument zu geben, sodass das original erhalten bleibt?
ich verzweifle gerade :/

und @nezzcarth ich muss für pandas anscheinend noch etwas anderes installieren oder?
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@codingnoob: das Beispiel fängt keine Fehler ab und geht davon aus, dass *jede* Zeile der Datei dem Muster "xx.xx.xx," entspricht. Du hast wahrscheinlich aber auch noch anderes drin. Daher die Fehlermeldung.
codingnoob
User
Beiträge: 4
Registriert: Sonntag 12. März 2017, 16:35

ok ich habe einfach probiert ein"-" vor jede Zeile zu setzen und es hat irgendwie funktioniert.

-01 18.833333333333332
-02 19.0

also habe ich jetzt als erstes die Kategorie (01) und danach den Durchschnitt.
Allerdings habe ich jetzt noch nicht den durchschnitt für jede einzelne Person.
Könnte mir da ein letztes mal nochmal jemand helfen?
Bittebittebitte
Antworten