Listen vergleich + Sortierung nach definierter Spalte

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
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

Hallo Leute,

habe ein Problem bei dem Vergleich von mehreren Listen die Sortiert nach der Ersten Spalte in eine Datei geschrieben werden sollen.

Das Skrippt an und für sich läuft. jedoch werden die kompletten Zeilen sortiert. Problem an der Sache ist, dass es dann für die erste Spalte ( Datum ) doppel Einträge gibt wenn die nachfolgenden Spalten unterschiedliche Werte zum Vergleichswert aufzeigen.

Datei auswahl erfolgt über wxfiledialog und die Files stehen in der Variable selected[n]

Code: Alles auswählen

if i > 1:
	n = 0
	with open(selected[0], 'r') as lines:
		unique_lines = set(lines)
		unique_lines.split(" ")
	for zeile in selected:
		with open(selected[n], 'r') as lines:
			lines.next()
			unique_lines.update(lines[0])
		n += 1	
		with open('output.txt', 'w') as output_file:
			output_file.writelines(sorted(unique_lines))
		
else:
Frage ist nun. wie kann ich nach der ersten Spalte sortieren lassen und danach aber wieder die gesamte Zeile in die Ausgabe schreiben?

beste Grüße
"Im Burnout steckt viel Arbeit drin" -Lysander
BlackJack

@OttoPython: Das Skript an und für sich kann nicht laufen. `unique_lines` wird an ein `set` gebunden und in der nächsten Zeile versuchst Du `split()` auf einem `set` aufzurufen — so eine Methode gibt es dort aber nicht. Oder hast Du `set` an etwas anderes gebunden als die eingebaute Funktion?

In der Schleife danach iterierst Du über `selected` und bindest die Elemente an den Namen `zeile` — das sind nach Deiner Aussage aber Dateien — was mit dem Quelltext auch nicht übereinstimmt, denn es scheinen Datei*namen* zu sein. Für beides ist `zeile` aber sicher kein passender Name. Und dann verwendest Du ihn auch gar nicht, sondern benutzt einen manuell hochgezählten Index um an die Elemente heran zu kommen, die Du sowieso schon an einen Namen gebunden hast, und eigentlich einfach verwenden könntest. Weshalb so umständlich?

Von den Dateien liest Du jeweils nur die erste Zeile ein und steckst davon das erste Zeichen in das `set` — vielleicht solltest Du mal den Sinn dahinter verraten beziehungsweise das Problem beschreiben, welches Du *eigentlich* lösen möchtest.

``output.txt`` wird für jeden Dateinamen in `selected` neu geschrieben. Das erscheint mir auch nicht sinnvoll die Datei immer wieder durch unfertige Zwischenergebnisse zu überschreiben, statt das Endergebnis einmal am Ende der Verarbeitung in eine Datei zu schreiben.

Falls Du eine Liste mit Listen als Elementen hast, welche die Zeilen beschreiben und deren Elemente die Werte in den Spalten, dann suchst Du einfach nur die `sort()`-Methode auf der äusseren Liste mit einer entsprechenden Funktion für das `key`-Argument dieser Methode. Da muss eine Funktion übergeben werden, die ein einzelnes Element bekommt und daraus den Sortierschlüssel berechnet und zurück gibt. In Deinem Fall ist das einfach das erste Element. Wobei ich mich Frage ob Du da überhaupt den Aufwand betreiben musst, denn wenn man einfach ohne Argumente sortiert, ist das Ergebnis letztendlich ja auch nach der „ersten Spalte” sortiert.

Falls Deine Daten anders aussehen, solltest Du Dein Problem noch einmal genauer beschreiben. Wie sehen die Eingangsdaten aus, was soll damit passieren, wie sollen die Ausgangsdaten im Verhältnis zu den Eingangsdaten danach aussehen. Vielleicht mit einem kleinen, nachvollziehbaren Beispiel. Und wenn es geht auch mit einer Beschreibung was das eigentlich alles soll. Was sind das für Daten, welchen Zweck verfolgt die Verarbeitung.
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

hey danke schonmal.

ja selected ist der Dateiname der aufgerufen wird.

das Problem hinter der Aufgabe ist. Das ich doppelte Einträge vermeiden muss!

in -zeile- werden wie im scrippt definiertdie Zeilen der einzelnen Dateien geschrieben

Problem an der Sache:
Sind die Zeilen absolut identisch, so tauchen die auch nicht in meinem Outputfile auf..sobald aber irgendeine Stelle innerhalb der Zeile anders ist wird sie wieder aufgenommen obwohl ich dann ein doppelEintrag vorfinde:

Code: Alles auswählen

201220081000  123  
201220081000  123
diese Zeilen werden als Doppelt erkannt und nicht wieder doppelt aufgenommen! nur 1 Eintrag im Output

Code: Alles auswählen

201220081000  123  
201220081000  124
wird aber beides aufgenommen! das soll aber nicht passieren da ich nun ein doppeleintrag für das Datum habe.
Dabei ist es völlig egal welchen der beiden Einträge er behält(ist sowieso der erste)

Ich brauch also ein Split der Zeilen und dann einen vergleich des Datums [Spalte1].. aber beim schreiben muss wieder die komplette Zeile geschrieben werden. Split im Set funktioniert aber nicht :(
"Im Burnout steckt viel Arbeit drin" -Lysander
BlackJack

@OttoPython: Du brauchst kein `set` sondern ein Wörterbuch was das Datum auf eine Zeile abbildet. Das machst Du mit jeder Zeile in — nehme ich jetzt mal an — jeder Datei. Dann ersetzt eine Zeile mit dem gleichen Datum einen eventuell schon vorhandenen Eintrag.

Edit (ungetestet):

Code: Alles auswählen

    date2line = dict()
    for filename in filenames:
        with open(filename) as lines:
            date2line.update((line.split(' ', 1)[0], line) for line in lines)
    
    with open('out.txt', 'w') as out_file:
        out_file.writelines(sorted(date2line.itervalues()))
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

hi,

ich erhalte ValueError: dictionay update sequence element #0 has lenght 13, 2 is required

was nun? wieso kann das dictionary nicht mit 13 zeichen umgehen?

und was bedeutet eigentlich die 1 bei line.split(' ',1)?
"Im Burnout steckt viel Arbeit drin" -Lysander
BlackJack

@OttoPython: Die Meldung kann bei dem gezeigten Quelltext nicht kommen. Da ist an der entsprechenden Stelle ein literales Tupel mit genau zwei Elementen. Ich sehe nicht wie 13 daraus werden könnten.

Argumente werden üblicherweise in der Dokumentation beschrieben: str.split()
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

kommt aber die meldung. auch wenn ich mein scrippt auf deine variablen anpasse ( hab ja dein code auf meine variablen angepasst)
ändere ich aber eine inputdatei .. also nehme ich in derr ersten zeile ein zeichen weg steht dann in der fehlermeldung 12 anstelle der 13.. das hat mit den zeichen zu tun. die zeile ist nämlich auch 13 zeichen lang
"Im Burnout steckt viel Arbeit drin" -Lysander
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.
OttoPython hat geschrieben:ich erhalte ValueError: dictionay update sequence element #0 has lenght 13, 2 is required
was nun? wieso kann das dictionary nicht mit 13 zeichen umgehen?
Das sagt die Fehlermeldung doch gar nicht aus. Update will eine Sequenz von Tupeln, du übergibst aber irgend etwas anderes. Da du allerdings nicht den gesamten Traceback zeigst und noch dazu kein Stück Code, kann man nicht einmal sagen in welchem Kontext der Fehler auftritt.
OttoPython hat geschrieben:und was bedeutet eigentlich die 1 bei line.split(' ',1)?
Das lässt sich doch leich in der Dokumentation nachlesen. Ansonsten hast du im interaktiven Interpreter auch immer die möglichkeit mittels ``help(expr)`` Hilfe zu dem übergebenem Objekt zu bekommen. ``help(str.split)`` bzw. ``help(line.split)`` verraten dir dann die Parameter.

Sebastian
Das Leben ist wie ein Tennisball.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

OttoPython hat geschrieben:kommt aber die meldung. auch wenn ich mein scrippt auf deine variablen anpasse ( hab ja dein code auf meine variablen angepasst)
Dann liegt es wahrscheinlich daran, dass du deinen Code nicht richtig angepasst hast. Wenn du die entsprechende Stelle aber nicht posten willst, dann kann man dir auch nicht helfen.
Das Leben ist wie ein Tennisball.
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

ups.. mein fehler :roll:

Code: Alles auswählen



Traceback (most recent call last):
  File "C:\Users\Rennziege 2\Desktop\TEST\datei-vergleich-test\merch-test.py", l
ine 33, in <module>
    date2line.update((line.split(' ',1)[0]) for line in lines)
ValueError: dictionary update sequence element #0 has length 13; 2 is required


Code: Alles auswählen

	date2line = dict()
	for file in selected:
		with open(selected[n]) as lines:
			date2line.update((line.split(' ',1)[0]) for line in lines)
	
	with open ('out_20120702.txt', 'w') as output_ile:
		output_file.writelines(sorted(date2line.itervalues()))
sehe grad im schreibcode ein f bei output_file fehlt.. getestet: hat keine einfluss, fehler entsteht ja 3shcon zeilen darüber
Zuletzt geändert von OttoPython am Montag 2. Juli 2012, 12:58, insgesamt 1-mal geändert.
"Im Burnout steckt viel Arbeit drin" -Lysander
BlackJack

@OttoPython: In der Tat Dein Fehler. Vergleich noch mal Deinen Code mit meinem…
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

tatsache: ich danke dir, eigentlich hat ich copy paste gemacht.. kann ich mir nicht erklären wie das ", line" verschwunden ist :roll:

danke!
läuft auch durch..
aber:
habe n auf 0 gesetzt als zähler
ich habe 3 files ausgewählt.. im inhalt der ausgabe kann ich aber nur den inhalt des 1 files finden. ( aber schonmal richtig ohne doppelte einträge). jedoch die gesamten anderen inhalte fehlen ( sind nicht doppelt zu irgendwelchen anderen 1. spalten aus einer der dateien)
"Im Burnout steckt viel Arbeit drin" -Lysander
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

n += 1 hat gefehlt.. alles gut.. höre schon auf zu nerven :D
"Im Burnout steckt viel Arbeit drin" -Lysander
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

Blackjack:

mir is jetz aufgefallen. das scrippt macht zur zeit genau das gleiche wie meines vorher.

in der Ausgabe gib es immernoch doppelte Einträge für die erste Spalte. :( es fehlen lediglich die Zeilen die absolut doppelt sind.
"Im Burnout steckt viel Arbeit drin" -Lysander
BlackJack

@OttoPython: Das ``n +=1`` hat nicht wirklich gefehlt sondern Du hast auch meine ``for``-Schleife nicht so übernommen wie ich sie geschrieben habe. ``selected[n]`` kommt bei mir nirgends vor, weil das `n` in diesem Fall unpythonisch ist. Man kann ohne den Umweg eines Index über Elemente einer Liste iterieren.

Doppelte Einträge für die erste Spalte kann es nicht geben, denn das würde bedeuten, dass Schlüssel in Wörterbüchern mehrfach vorkommen können — das ist aber unmöglich. Wörterbücher sind so definiert, dass der Schlüssel eindeutig ist.
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

das n steht für die zeile von selected, da zb. in selected[1] der pfad zur ersten datei liegt, und so weiter. es werden damit alle dateien nacheinander aufgerufen.. wie sollte es sonst gehen? meine Dateien hol ich mir per wxfiledialog und diese stehen dann in selected als Zeilen untereinander mit den Pfaden.

Code: Alles auswählen

20120213	256
20120213	257
20120214	256
20120215	256
20120216	256
20120218	256
20120219	257
20120220	256
20120221	256
20120221	257
20120222	257
20120223	256
20120229	256
20120230	256
das ist die Ausgabe am Ende des Programms. Mach ich ein

Code: Alles auswählen

print date2line
in der ersten with open anweisung, so erhalte ich anstelle nur der ersten spalte die komplette Zeile.. die dürfte doch dort aber eigentlich gar nciht stehen?!
"Im Burnout steckt viel Arbeit drin" -Lysander
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

Code: Alles auswählen

if i > 1: # else wenn nur eine Datei gewählt. keine sortierung vornehmen
	n = 0
	date2line = dict()
	for file in selected:
		with open(selected[n]) as lines:
			date2line.update((line.split(' ',1)[0], line) for line in lines)
			print 'checked File: ', selected[n]
			n += 1
"Im Burnout steckt viel Arbeit drin" -Lysander
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Bei dir hat man ein wenig das gefühl, dass du eher rätst als darüber nachzudenken was du machst.

1. for-Schleife

Code: Alles auswählen

for filename in selected:
    with open(filename) as lines:
        ....
Was hat du gedacht, was das for bewirkt? Hast du dir mal filename ausgeben lassen? Dann hättest du doch merken müssen, dass das zusätzliche n Unfug ist.

2. Zur Ausgabe: Dich wundert wirklich, dass in der Ausgabe alle Zeilen stehen, wenn du mit print jede Zeile ausgibst? Pythons print nutzt nicht auf magische Weise dein date2line-Dictionary um Ausgaben zu filtern ;-)

3. Zu den vollständigen Zeilen: Was denkst du, was

Code: Alles auswählen

(line.split(' ',1)[0], line)
macht?

Alle deine Fehler lassen sich einfach lösen, wenn man mal über das Problem nachdenkt und versteht, was der eigene Code macht. Das tust du offensichtlich nicht. Wenn du etwas nicht verstehst oder du unerwartete Ergebnisse bekommst, dass lasse dir die Zwischenschritte mittels print Ausgeben. Meistens sieht man dann die Lösung auf den ersten Blick.
Das Leben ist wie ein Tennisball.
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

1. ja ich lass mir die filenamen vorher bereits einmal ausgeben und zwar über den Zähler.. das läuft.
2. nein so war das nicht gemeint: die ausgabe über print date2line bewirkt [ 2012.../t256 : 2012.../t256] was ja eigentlich [2012 : 256] hätte sein müssen
3. line.split teilt mir die aktuelle zeile bei nem 'leerzeichen", die 1 bewirkt das alles die erste spalte in der Zeile als ganze zeichenkette erfasst wird und das [0] steht für die erste spalte als ausgabe

habe übrigens genau bei der überlegung festgestellt, ist das split in der Datei wirklich ein "leerzeichen"? nein war es nicht es war ein "Tab" darin lag die fehlerquelle.

jetzt ist die Ausgabe

Code: Alles auswählen

20120213	257
20120214	256
20120215	256
20120216	256
20120218	256
20120219	257
20120220	256
20120221	256
20120222	257
20120223	256
20120229	256
20120230	256
jetzt ist es richtig. nun ist dabei aber zubeachten, dass zb 20120213 hatte als ersten Input :256 und als zweiten input :257 -> da es sich um update handelt, wird natürölich die vorherige Zeile überschrieben und der letzte Wert in das Outputfile übertragen.

Nun läuft es!
Merci Beaucoup!
Otto
"Im Burnout steckt viel Arbeit drin" -Lysander
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

OttoPython hat geschrieben:1. ja ich lass mir die filenamen vorher bereits einmal ausgeben und zwar über den Zähler.. das läuft.
Ja, es läuft, aber es ist hässlich.

Variante 2 im folgenden Code ist einfacher zu lesen (und schneller)

Code: Alles auswählen

data = ['P', 'E', 'P', '-', '8']

for i in range(len(data)):
    print data[i]

for char in data:
    print char
Antworten