Reihenfolge in einem Dictionary

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
jaessyfizzle
User
Beiträge: 6
Registriert: Freitag 24. Februar 2012, 21:45

Hallo ihr lieben Helfer,

ich habe eine Frage zur Reihenfolge in Dictionarys in Python.

Ich habe ein Skript, welches Variablen in einem Text austauscht. Der Text ist in einer Liste gespeichert. Ich habe ein Dictionary angelegt, in den Keys stehen die ursprünglichen Variablen, in den Values die Variablen mit denen die original Variablen ersetzt werden sollen.
Eine funktion prüft nun für jedes Element der Liste, ob ein (oder auch mehrere) Keys in dem Element vorkommen und ersetzt dieses mit dem entsprechenden Wert. Soweit funktioniert das auch alles ganz wunderbar und ich war mächtig stolz. 8)

Bis mir dann folgendes Problem aufgefallen ist:
Die Keys werden nicht in der Reihenfolge gespeichert, wie sie ins Dictionary geschrieben werden. Das ist natürlich blöd, wenn manche Variablen teile anderer Variablen sind.
So habe ich z.B die Varaible "{Vorname} {Name}", welche durch "[NAME]" ersetzt wird und eine Variable "{Name}", welche ebenfalls durch "[NAME]" ersetzt wird. Anscheinend wird nun zuerst nach "{Name}" gesucht und ersetzt.
Nun steht in dem Element "{Vorname} [NAME]", wenn nun also nach "{Vorname} {Name}" gesucht wird, wird logischerweise nichts gefunden.
Da die Suche bei Google ergeben hat, dass die Reihenfolge in einem Dict mehr oder weniger zufällig ist (und sich auch ändern kann), ist die einzige Lösung die mir spontan einfällt, dass ganz über 2 Dictionarys zu machen, erst das eine, dann das andere.
Oder ist es mehr oder weniger einfach, zu prüfen, ob wenn ein Key gefunden wurde, davor (oder dahinter) noch etwas steht, was auch zu anderen Keys gehört?

Hat irgendwer eine Idee wie man so ein Problem löst? Hatte hier in der Forumsuche etwas davon gelesen, das ganze über Tupel zu machen, allerdings weiß ich nicht, ob das bei mir Zielführend ist.

Vielen Dank
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Wirf mal einen Blick ins collections-Modul, dort gibt es ein OrderedDict.

Sebastian
Das Leben ist wie ein Tennisball.
deets

Ich verstehe dein Problem nicht ganz, bzw. finde, dass du da etwas falsch programmiert hast.

Wieso moechtest du denn {Vorname}{Name} nur durch [NAME] ersetzen? Bzw. wenn du das willst, warum reicht es nicht, {Vorname} auf "" (den leeren String) abzubilden, und dann ist alles ok?

So wie du das beschreibst, ist das ein deutlich zu kompliziertes System, wenn man da sowas macht bzw. auch noch die Reihenfolge bei der Ersetzung im Blick haben muss.

Was ist denn das eigentliche Problem, das du da loesen willst?
jaessyfizzle
User
Beiträge: 6
Registriert: Freitag 24. Februar 2012, 21:45

Vielen Dank für die Tipps!

@deets: Ja, die Idee hatte ich erst auch, hab sie dann aber verworfen, weil ich dachte, blöd wenn dann mal irgendwo eine Variable nur mit "{Vorname}" vorkommt. Dann wäre ich ja wieder beim gleichen Problem wie jetzt auch.
Das eigentliche Problem ist, dass ich Variablen in einem Text habe, und diese mit anderen Variable ersetze. Ist eigentlich auch gar nicht so kompliziert wie ich das gemacht habe, ich glaube es hört sich schlimmer an, als es eigentlich ist!

Habe mir jetzt kurz das collections-Moduil angeguckt und auch schon einem kleinen Test unterzogen. Es sieht fast so aus, als ob dies die Lösung für mein Problem wäre. Wie schön einfach manche Dinge doch sind! :)

Nochmals vielen Dank für eure Hilfe!
BlackJack

@jaessyfizzle: Brauchst Du denn unbedingt ein Wörterbuch dafür? Könntest Du die Alt/Neu-Paare nicht auch einfach als Tupel in einer Liste ablegen in der Reihenfolge, in der die Ersetzungen durchgeführt werden sollen?
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@jaessyfizzle: Ich glaube nicht, dass dein Problem vom dict herrührt, sondern davon, wie du die Variablen-Namen aus dem Text extrahierst. Ich würde sowas versuchen:

Code: Alles auswählen

import re

scan = re.compile(flags=re.VERBOSE, pattern='''
    {(?P<var>\w+)}  |
    (?P<space>\s+)  |
    (?P<other>\S+)
''').finditer

translate = {
            ('name',):'[NAME]',
            ('vorname',):'[NAME]',
            ('vorname', 'name'):'[NAME]',
            ('jause',):'[BRAUSE]'
}

text = 'foo {vorname} {name} bar {name} zig {vorname} zag {jause} hallo'

varstack = []
for match in scan(text):
    if match.lastgroup == 'var':
        varstack.append(match.group('var'))
    elif varstack and match.lastgroup == 'other':
        print varstack, '-->', translate[tuple(varstack)]
        varstack = []
Ergebnis:

Code: Alles auswählen

['vorname', 'name'] --> [NAME]
['name'] --> [NAME]
['vorname'] --> [NAME]
['jause'] --> [BRAUSE]
In specifications, Murphy's Law supersedes Ohm's.
jaessyfizzle
User
Beiträge: 6
Registriert: Freitag 24. Februar 2012, 21:45

@Blackjack: Nein, es muss nicht zwingend ein Dictioanary sein. Die Idee mit den Tupeln hatte ich auch schon (hatte hier im Forum ein ähnliches Problem gelesen). Aber irgendwie erschien mir der Weg über ein Dictionary sinnvoller. Weiß aber auch irgendwie nicht mehr so ganz warum. :)

@Pillmuncher: Hmm, irgendwie sieht dein Code kompliziert aus, ich bin noch relativ am Anfang meiner Programmierkarriere.
Ich hatte mir so etwas zusammen gebastelt, was jetzt das beste ist, kann ich nicht sagen:

Code: Alles auswählen

import re

index = 0

text_liste = ["{Name} hat am {Datum} Geburtstag und wird {Alter} Jahre alt!",
         "{Name} wohnt in {Stadt}.", "{Name} hat blaue Augen."]

variablen = {"{Name}": "[NAME]", "{Datum}": "[DATUM]",
             "{Alter}": "[ALTER]", "{Stadt}": "[STADT]"}

original_variablen = variablen.keys()
variablen_paare = variablen.items()

for Element in text_liste:
        
    variablen_index = 0

    for variabel in original_variablen:
                
        while variabel in Element:
            Element = re.sub(
                variabel,
                variablen_paare[variablen_index][1], Element)

        variablen_index += 1
    text_liste[index] = Element
    index +=1
Das liefert mir folgendes Ergebnis:

Code: Alles auswählen

[NAME] hat am [DATUM] Geburtstag und wird [ALTER] Jahre alt!
[NAME] wohnt in [STADT].
[NAME] hat blaue Augen.
Werde mir deinen Code nochmal genauer anschauen, momentan sind da noch einige Sachen, die ich nicht verstehe. :)
deets

jaessyfizzle hat geschrieben:@Blackjack: Nein, es muss nicht zwingend ein Dictioanary sein. Die Idee mit den Tupeln hatte ich auch schon (hatte hier im Forum ein ähnliches Problem gelesen). Aber irgendwie erschien mir der Weg über ein Dictionary sinnvoller. Weiß aber auch irgendwie nicht mehr so ganz warum. :)
Ist er aber nicht. Und es ist wichtig, darueber nachzudenken und zu verstehen, warum. Datenstrukturen sind das A&O der Programmierung.

Und hier ist es eben entscheidend, welche Operationen man sich auf seinen Daten wuenscht, bzw. welche man benutzt.

In deinem Fall ist alles, was du benoetigst, das iterieren ueber die Paare von auszutauschenden Variablen. Denn du brauchst fuer jede gefunden Variable die Ersettzung in der richtigen Reihenfolge. Dafuer ist eine Liste von Tupeln ideal.

Hingegen bringt ein dict dir immer dann etwas, wenn du wahlfrei auf bestimmte Elemente zugreifen willst.

Ein ordered dict vereinigt zwar nun die Vorteile von beiden Strukturen. Aber das tut es nicht umsonst! Im Gegenteil, hinter den Kulissen gibt es einigen Aufwand zu treiben - Aufwand, der sich unter Umstaenden katastrophal auf die Laufzeit auswirkt. Und daher sollte man es auch nicht verwenden - sondern stattdessen eine liste von tupeln.

Natuerlich ist das fuer dein kleines Beispielchen hier nicht wirklich wichtig. Aber das grundlegende Verstaendnis, wann welche Datenstruktur man braucht, sollte man sich schon moeglichst frueh antrainieren.
jaessyfizzle
User
Beiträge: 6
Registriert: Freitag 24. Februar 2012, 21:45

@deets: Ja, du hast ja Recht, aber irgendwie war da was, weshalb ich dachte es wäre besser über ein Dictionary zu gehen. Leider habe ich da dann nicht an alles gedacht, bzw. wusste auch nicht alles über Dictionarys.

Ich habe das ganze jetzt geändert und über Tupel gemacht. Aber das wichtigste ist doch schiließlich, dass ich wieder was gelernt habe und beim nächsten mal hoffentlich direkt richtig mache! 8)
Danke für eure Tipps und Hinweise
Antworten