Ergebnisse aus verschiedenen Textdateien gruppieren

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
Dareios
User
Beiträge: 5
Registriert: Sonntag 29. September 2013, 09:27

Ich habe verschiedene Textdateien in einem Ordner, die ich nach Referenzen durchsuchen lassen möchte (zB "A 33"). So eine Referenz kann in mehreren Textdateien auftauchen. Zuerst drei Textdateien als Beispiel:

Code: Alles auswählen

 #text file no 1
1. line 1
>>A 33
2. line 2
>>A 34
3. line 3
>>A 35

Code: Alles auswählen

 #text file no 2
1. line 1
>>A 34
2. line 2
>>A 35
3. line 3
>>A 36

Code: Alles auswählen

 #text file no 3
1. line 1
>>A 36
2. line 2
>>A 37
3. line 3
>>A 38
Der folgende Code, den ich derzeit verwende, sucht alle Referenzen in einem bestimmten Rahmen (A 180 - A 185).

Code: Alles auswählen

    for score in os.listdir(path):
        with open(os.path.join(path, score), "rb") as text:
            for prev_line, line in linePairs(text):
            	for i in range( 180, 185 ):
               		if re.search('A {}'.format(i), line):
            	    		print('{}{}'.format(line, prev_line))
Das funktioniert auch wunderbar und ich bekomme die Ergebnisse, aber dennoch hätte ich gerne die verschiedenen Versionen einer Referenz (zB A 180) gruppiert, so wie im folgenden Beispiel:

Code: Alles auswählen

 #Output
>>A 33
1. Line 1 # file no 1

>>A 34
2. Line 2 # file no 1
1. Line 1 # file no 2

>>A 35
3. Line 3 # file no 1
2. Line 2 # file no 2

>>A 36
3. Line 3 # file no 2
1. Line 1 # file no 3

>>A 37
2. Line 2 # file no 3

>>A 38
3. Line 3 # file no 3
Mit dem oben angeführten Code werden die Dateien eine nach der anderen wiedergegeben. Liegt es an der Reihung der Zeilen oder an den Einschüben?

Hat jemand eine Idee, wie das bewerkstelligt werden kann? Ideal wäre nur einmal die Referenz zu haben und dann die verschiedenen Belege in den Textdateien, bevor das Programm Ergebnisse zur nächsten Referenz liefert.

Vielen Dank für jeden Hinweis.
D.
Zuletzt geändert von Anonymous am Sonntag 29. September 2013, 10:06, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hallo,

das sollte nicht so schwer sein! Du musst Dir einfach eine Datenstruktur aufbauen, die genau das ermögicht. Ich denke da sofort an ein Dictionary, welches als Schlüssel die von Dir zu untersuchenden Referenzen besitzt und als Werte eine Liste mit den gefundenen Referenzen.

Dies ist an sich auch eleganter als Deine bisherige Fassung, bei der Du Dir für *jede* Zeile die Schlüssel erst mühsam aufbaust. Diese Generierung erledigst Du beim obigen Ansatz nur *einmal*:

Code: Alles auswählen

from collections import defaultdict
keys = ["A {}".format(i) for i in range(180, 185)]
results = defaultdict.fromkeys(keys, list)
# später in der Suchschleife:
if re.search(key, line):
    results[key].append(prev_line)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Dareios
User
Beiträge: 5
Registriert: Sonntag 29. September 2013, 09:27

Vielen Dank für die schnelle Antwort. Einfache Dinge in Python sind für mich noch immer sehr komplex. Ich werde mir deinen Ansatz ansehen.
D.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Naja, die grundlegenden Datenstrukturen - und ein Dictionary gehört nun mal dazu ;-) - sollte man sich als Anfänger so schnell wie möglich angucken und verstehen lernen. Letztlich brauchst Du die für jedes halbwegs komplexe Programm.

Das ``defaultdict`` ist an sich nur eine Spezialisierung eines normalen Dictionary, welche primär das Erstellen eines Dictionary-Objektes vereinfacht. Ich kann eben a priori für jeden Schlüssel festlegen, welches Wertobjekt dieser bekommen soll. IdR. wird das gerne für Probleme wie dem Deinen benutzt, beim dem als Schlüssel eine Container-Datenstruktur zum Einsatz kommen soll, wie hier eine Liste.

Ohne ``defaultdict`` muss ich beim Hinzufügen von Werten immer erst prüfen, ob schon ein Wert angelegt worden ist und wenn nicht, zunächst das Listenobjekt erzeugen und dem Schlüssel zuweisen. Alternativ in Fällen, bei denen die Schlüssel zu Beginn bekannt sind, kann ich auch ein Schleifenkonstrukt benutzen, um die Werte alle zu initialisieren:

Code: Alles auswählen

results = dict()

for key in keys:
    results[key] = list()

results
{'A 180': [], 'A 181': [], 'A 182': [], 'A 183': [], 'A 184': []}

# oder als LC:
results = {"A {}".format(i): list() for i in range(180, 185)}

results
{'A 180': [], 'A 181': [], 'A 182': [], 'A 183': [], 'A 184': []}
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Dareios
User
Beiträge: 5
Registriert: Sonntag 29. September 2013, 09:27

Ich habe nun folgendes versucht (mir ist das Konzept von Dictionary nun bewusst), aber zum Beispiel bekomme ich die Fehlermeldung, dass "key" nicht definiert ist. Und ich weiss nicht, wie ich den zweiten Code einbauen soll, in dem die keys einzeln definiert werden.

Code: Alles auswählen

    for score in os.listdir(path):
		from collections import defaultdict
		keys = ["A {}".format(i) for i in range(180, 185)]
		results = defaultdict.fromkeys(keys, list)
		with open(os.path.join(path, score), "rb") as text:
        		for prev_line, line in linePairs(text):
        			if re.search(key, line):
					    results[key].append(prev_line)
Wenn ich in der Suche "key" zu "keys" ändere, bekomme ich die Fehlermeldung, dass list ein "unhashable type" ist. Ich weiss, das sind alles dumme Fragen.

D.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Dareios: Deine Einrückungen sind fehlerhaft. Du solltest in jeder Ebene immer genau 4 Leerzeichen benutzen.
»fromkeys« ist in Deinem Fall nicht sinnvoll, richtig wäre Hyperions zweiter Vorschlag mit Listcomprehension.
Irgendwelche Strings als regulären Ausdruck zu nehmen führt früher oder später zu Problemen.
Das Setzen von »results« steht auch an der falschen Stelle, Du erzeugst damit für jede Datei eine neues Dict, Du willst aber doch alle Dateien in einem Dict sammeln.
»import«s sollten auch in den ersten Zeilen einer Pythondatei stehen.
Hier mal der zentrale Teil:

Code: Alles auswählen

match = re.match(r'>>(A \d+)',line)
if match and match.group(1) in results:
    results[match.group(1)].append(prev_line)
Die restlichen Verbesserungen solltest Du selbst umsetzen können.
Dareios
User
Beiträge: 5
Registriert: Sonntag 29. September 2013, 09:27

Ich finde keine Beispiele, die keys oder values aus verschiedenen Textdateien heranziehen! Der folgende Code sieht chaotisch aus, weil ich nicht mehr durchblicke!

Code: Alles auswählen

    for score in os.listdir(path):
		#from collections import defaultdict
		#keys = {"A {}".format(i): list() for i in range(180, 185)}
		results = {}
		with open(os.path.join(path, score), "rb") as text:
        		for prev_line, line in linePairs(text):
        			#results = {}
        			for i in range(180, 184):
        				match = re.search('A {}'.format(i), line)
        				if match:
        					Ref = match.group().lstrip('>>A ')
        					results[line] = Ref
        					#if ref1 in results:
        					#	results[ref1].append(value)
        					#else:
        					#	results[ref1] = [value]
        					#for key, value in results.items():
        					#	print (value)
        					#results[match.group()].append(prev_line)
    						for key, value in sorted(results.iteritems(), key=lambda (k,v): (v,k)):
        						sortedByValue = sorted(results.items(), key = lambda t: t[1])
        						print sortedByValue
Die Einrückungen stimmen vermutlich nicht! Ich wollte, dass "value" sortiert wird, aber noch immer wird jede Datei separat sortiert. Wäre es richtig, das dictionary (results) zu aktualisieren?

D.
Zuletzt geändert von Anonymous am Montag 30. September 2013, 09:56, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@Dareios: Das ist ja auch viel zu komplex für ein zusammenhängendes Stück Quelltext. Teil das sinnvoll in Funktionen auf, die man einzeln testen und verstehen kann. Ganz grob kann man die meisten Programme in Eingabe, Verarbeitung, Ausgabe unterteilen. Du hast die Ausgabe mit in diesem riesen Code-Haufen und das auch noch an einer völlig falschen Stelle.

Fang mit einer Funktion an die ein iterierbares Objekt mit Zeilen bekommt und das in ein Wörterbuch (`dict`) umwandelt. Diese Funktion kannst Du dann mit *einer* Datei testen. Dann eine Funktion welche die Daten aus dem Wörterbuch in der von Dir gewünschten Form ausgibt. Wieder testen! Dann eine Funktion die zwei solcher Wörterbücher bekommt und wahlweise ein komplett neues aus den Daten von beiden erstellt, oder das erste mit den Daten vom zweiten erweitert. Das kannst Du dann mit zwei Dateien testen. Wenn das funktioniert, kann man es auf viele Dateien erweitern.

*So* funktioniert Programmieren. Nicht in dem man sein Programm aus anderer Leute Code irgendwie wild zusammenstückelt und rumprobiert in der Hoffnung das es irgendwann klappt. Wobei man dann nicht mal sagen kann ob es tatsächlich klappt, oder nur auf den ersten Blick richtig aussieht, solange man nicht versteht was wirklich passiert. Und Dein Quelltext sieht so aus als wenn Du nur wild herumprobierst, und weder Schleifen noch Wörterbücher wirklich verstanden hast.
Antworten