Objekte (aus Dateien geparsed) gruppieren in eine Liste

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
dax5
User
Beiträge: 7
Registriert: Sonntag 3. Februar 2013, 18:13

Hallo,

ich habe leider keine passende Lösung für mein spezielles Problem gefunden und würde mich freuen, hier mein Glück zu finden :)
Konkret habe ich folg. Problem:

Alle Dateien eines Ordners enthalten XML-Dateien, die alle eingelesen/geparsed werden sollen, was prinzipiell schon funktioniert. Je nach Dateiname, welcher die "Kategorie" der Obj. beschreibt, sollen die gelesenen XML-Objekte gruppiert, also am Einfachsten in eine Liste "kategorieX" gespeichert werden.
Die Dateien sehen z.B. wie folgt aus:
fahrzeugX1_markeY1_baujahrZ1.xml
fahrzeugX1_markeY1_baujahrZ2.xml => Die 3 XML-Objekte dieses 3er Blocks (Kategorie: selbes Fahrzeug und selbe Marke) sollen in eine Liste, da sie zur selben KategorieXY gehören
fahrzeugX1_markeY1_baujahrZ3.xml
...
fahrzeugX1_markeY2_baujahrZ4.xml
fahrzeugX1_markeY2_baujahrZ5.xml
fahrzeugX1_markeY2_baujahrZ6.xml
...
fahrzeugX2_markeY3_baujahrZ7.xml

Dafür habe ich erst mal eine Liste erstellt, die alle Dateinamen aufnimmt:

Code: Alles auswählen

filesAll = [ f for f in listdir(pfad) if isfile(join(pfad,f)) ] 
Abhängig vom Dateinamen wird dann die entsprechende Datei geparsed und in eine Liste/Gruppe gespeichert:

Code: Alles auswählen

for f in filesAll:
    if 'fahrzeugX1_markeY1' in f:
        xmlObjList_fahrzeugX1_markeY1.append( parse(pfad + f) )    # = Liste von parsed XML-Objekten derselben Kategorie fahrzeugX1_markeY1
    elif 'fahrzeugX1_markeY2' in f:
        xmlObjList_fahrzeugX1_markeY2.append( parse(pfad + f) ) 
    usw.
Da ich etliche Kategorien vorzunehmen habe, wäre diese Lösung zwar lauffähig aber extrem aufwändig und unflexibel.
Das eigentliche Problem ist aber, dass in den if-Verzweigungen noch Funktionsaufrufe implementiert werden müssen, wo als akt. Parameter "xmlObjList_KategorieX", also eine Liste mit gruppierten XML-Objekten übergeben werden müssen, also in jeder Verzweigung folgender Aufruf:

Code: Alles auswählen

       funktion(xmlObjList_KategorieXY)
Mir wäre schon sehr geholfen, wenn ich die Liste "filesAll" mit allen Dateinamen/Strings umwandeln könnte in eine Liste mit XML-Objekten, die diesen Dateinamen entsprechen, also [xmlObjList_Kategorie1, xmlObjList_Kategorie2, ...], damit ich diese Liste der Funktion "funktion()" als Parameter übergeben kann.

Hoffe, die Beschreibung war nicht zu kompliziert und würde mich über Ideen freuen. Danke schon mal!
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Hier eine Loesung, die dir deine Dateinamen gruppiert - sofern die Namen tatsaechlich konsistent so einem Muster entsprechen.

Code: Alles auswählen

import re
from collections import defaultdict

def group_filenames(filenames, pattern):
    grouping = defaultdict(list)
    for filename in filenames:
        match = re.match(pattern, filename)
        if match:
            grouping[match.group(1) + match.group(2)].append(filename)
    return grouping.values()

filenames = ['fahrzeugX1_markeY1_baujahrZ1.xml', 'fahrzeugX1_markeY1_baujahrZ2.xml', 'fahrzeugX1_markeY1_baujahrZ3.xml', 'fahrzeugX2_markeY1_baujahrZ1.xml']
pattern =  r'fahrzeug(.*?)_marke(.*?)_.*'

>>> group_filenames(filenames, pattern) 
[['fahrzeugX2_markeY1_baujahrZ1.xml'],
 ['fahrzeugX1_markeY1_baujahrZ1.xml',
  'fahrzeugX1_markeY1_baujahrZ2.xml',
  'fahrzeugX1_markeY1_baujahrZ3.xml']]
Ich hoffe ich habe dich da jetzt richtig verstanden.
dax5
User
Beiträge: 7
Registriert: Sonntag 3. Februar 2013, 18:13

Hey danke erst mal fürs Lesen meines Romans und deiner Hilfe!
Knackpunkt bei deiner Lösung ist, das Pattern einer Kategorie aus dem Dateinamen zu ziehen. Im Grunde also wieder mein Dilemma, dass ich nicht in der Lage bin, Strings/Dateinamen in einen Variablenbezeichner umzuwandeln. Da es (vorerst) mind. 25 Kategorien gibt, müsste ich dann wieder 25 Patterns erstellen.
Benutzeravatar
/me
User
Beiträge: 3556
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

dax5 hat geschrieben:Im Grunde also wieder mein Dilemma, dass ich nicht in der Lage bin, Strings/Dateinamen in einen Variablenbezeichner umzuwandeln. Da es (vorerst) mind. 25 Kategorien gibt, müsste ich dann wieder 25 Patterns erstellen.
Hier ist ohnehin wohl eher eine Liste oder ein Dictionary als Datenstruktur geeignet statt lauter einzelne Variablen.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@dax5: Sinn eines Pattern ist es ja gerade dass es ein Muster gibt, das die Gruppierung eindeutig macht. Bei Dir am Beispiel eben das Paar (fahrzeug??, marke??).
Diese Paar dient Dir dann als Schlüssel für ein Dictionary (z.B. xmlObjListe[fahrzeug, marke]). Wenn Du in Deiner Lösung anfängst, variable Variablennamen zu benutzen,
machst Du schon etwas falsch.
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

So verstehe ich das Problem:

Code: Alles auswählen

def my_pattern(filename):
    return "important part of filename"

files_all = [ f for f in listdir(pfad) if isfile(join(pfad,f)) ]

groups = dict()

for filename in files_all:
    group = my_pattern(filename)
    if groups.get(group) is None:
        groups[group] = list()
    groups[group].append(filename)
jetzt musst Du nur noch überlegen, wie my_pattern() mit dem Filenamen umgehen soll (z.B. alles was vor dem 2. Underscore steht?)
Dann hast Du alle zusammengehörigen Filenamen in einer Liste im Dictionary groups.
Damit kannst Du dann gebündelt weiterarbeiten.

edit: typo
dax5
User
Beiträge: 7
Registriert: Sonntag 3. Februar 2013, 18:13

Ok, vielen Dank allen! Denke, das Dict + Pattern ist die beste Idee und ich versuch es mal auf mein Projekt zu übertragen. Weitere Nachfragen halte ich mir mal offen :)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Wenn du das `.values()` aus der `return` Anweisung in meiner Funktion streichst, hast du es schon ;) Vorausgesetzt es gibt tatsaechlich ein Namensmuster bei den Dateinamen, wenn nicht wirst du wohl auf eine eigene Extraktionsfunktion zurueckgreifen muessen, wie mcdwerner es angedeutet hat.
Antworten