Dictionary mit Platzhaltern durchsuchen

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.
omnidan
User
Beiträge: 12
Registriert: Donnerstag 6. Januar 2011, 15:32

Liebes Forum,

ich habe eine simples Telefonbuch-Dictionary:

Code: Alles auswählen

telefonbuch = {"Musterman" : 1234,  "Wonderwoman" : 9876,  "Spiderman" : " spider(at)man.net"}
Zugriff auf die Elemente, sortieren, hinzufügen und löschen funktioniert soweit.

Jetzt möchte ich aber eine Suchfunktion hinzufügen, bei der auch Einträge gefunden werden, bei denen der Suchbegriff nur einen Teil ausmacht. Z. B.:

Eine Suche nach "woman" soll "Wonderwoman: 9876" ausgeben. Oder:
Eine Suche nach "man.net" soll "Spiderman" spider(at)man.net" ausgeben.

Schön wäre es, wenn man es einfach mit Platzhaltern machen könnte... und wenn die Suche auch NICHT case-sensitive wäre...

Any ideas?
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Alle Keys ablaufen (da gibt es eine Methode, diese zu erfragen), jeden einzelnen prüfen, zuvor die Strings auf "lower case" normieren. Dito für die Werte. Anders geht es nicht - und würde es auch eine DB nicht machen.

Stefan
omnidan
User
Beiträge: 12
Registriert: Donnerstag 6. Januar 2011, 15:32

Danke für die Tipps - schade, dass es nicht einfacher geht :(

Die Keys und Werte bekomme ich - aber wie läuft dann die Suche mit Platzhaltern auf den jeweiligen Listen? Hab ich da nicht das gleiche Problem wie beim Dictionary?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Na das ist doch nicht kompliziert:

Code: Alles auswählen

>>> telefonbuch = {"Musterman" : 1234,  "Wonderwoman" : 9876,  "Spiderman" : " spider(at)man.net"}
>>> def find(name):
...     for key, value in telefonbuch.iteritems():
...         if name in key:
...             return key, value
... 
>>> find("Muster")
('Musterman', 1234)
>>> find("man")
('Spiderman', ' spider(at)man.net')
Die Erweiterung von keiner Unterscheidung von Groß- und Kleinschreibung oder die Verwendung von regulären Ausdrücken ist auch relativ leicht. Was genau meinst du mit Platzhaltern auf Listen? Telefonnummern sind übrigens keine Zahlen ;-)

Sebastian
Das Leben ist wie ein Tennisball.
omnidan
User
Beiträge: 12
Registriert: Donnerstag 6. Januar 2011, 15:32

Vielen Dank für die Hilfe :)

Hab mein Problem damit gelöst (einschl. Groß-/Kleinschreibung):

Code: Alles auswählen

def eintragSuchen():
    suchbegriff = input("Suchbegriff eingeben: ")
    print("\n")
    
    for name, nummer in telefonbuch.items():
        if suchbegriff.lower() in name.lower() or suchbegriff.lower() in nummer.lower():
            print ("\t" + str(name) + ":\t" + str(nummer))
Hatte vorhin ein Verständnisproblem mit den Listen und den Platzhaltern - dachte ich soll direkt etwas mit telefonbuch.keys() konstruieren (was mir ja eine Liste zurück gibt) ... aber so tut es jetzt :)
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Und mit einer List Comprehension könnte man das auch machen:

Code: Alles auswählen

for element in ['\t%s\t%s' % (result[0], result[1]) \
    for result in telefonbuch.items() \
    if suchbegriff.lower() in result.lower()]:
    print element
Gruß
mutetella


P.S. Den muss ich an dieser Stelle jetzt noch loswerden:

Versuch' ich neulich, Spiderman anzurufen... hat der kein Netz!!! :shock:
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@mutetella
1. Bei Stringformatierungen kann Python auch gleich Tuples auseinander nehmen, es reicht also "'\t%s\t%s' % result".

2. "result.lower()" geht nicht, da das dort ein tuple und kein string ist.

3. Eher eine Frage - wenn man über eine Dictionary, um den Schlüssel und den Wert zu bekommen, iteriert sollte man in Python 2.x nicht "iteritems" benutzen ?
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Xynon1 hat geschrieben:1. Bei Stringformatierungen kann Python auch gleich Tuples auseinander nehmen, es reicht also "'\t%s\t%s' % result".
Oh Mann... voll peinlich... :oops:
Xynon1 hat geschrieben:2. "result.lower()" geht nicht, da das dort ein tuple und kein string ist.
Schlampige Arbeit... :oops:
Xynon1 hat geschrieben:3. Eher eine Frage - wenn man über eine Dictionary, um den Schlüssel und den Wert zu bekommen, iteriert sollte man in Python 2.x nicht "iteritems" benutzen ?
Hab' ich jetzt so gemacht...

Code: Alles auswählen

for element in ['\t%s\t%s' % (result) 
    for result in telefonbuch.iteritems()
    if any(suchbegriff.lower() in item.lower() 
    for item in result)]:
    print element
Ich finde allerdings, dass omnidans Lösung schöner zum Lesen ist. Dass meine dafür schneller ist, trau' ich mich nicht zu sagen, sonst machen sich gewisse Herren hier wieder über mich lustig... :D

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Schau bitte nochmal drüber :)
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hmm.... also funktionieren tut's.... meinst Du vielleicht meine nicht ganz PEP8-konformen Zeilenumbrüche?

Code: Alles auswählen

for element in ['\t%s\t%s' % (result) for
    result in telefonbuch.iteritems() if
    any(suchbegriff.lower() in item.lower() for
    item in result)]:
    print element
Bitte, gib' mir einen kleinen Tipp, ich kann sonst heute nicht einschlafen... :(

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Zum Beispiel sind die Klammern um das "result" überflüssig. "result" ist außerdem unpassend, da es gar nicht das Ergebnis ist. Dann könnte man sich noch fragen, warum du einen String zurück gibst und nicht das das Tupel, denn normalerweise möchte man mit den Daten arbeiten und sie nicht ausgeben. Vielleicht möchte man einfach die ganze LC als Ergebnis der Funktion verwenden. Dann stellt man sich natürlich noch die Frage, warum man, wenn die Daten schon gleich verarbeitet werden, einen ellenlange unübersichtliche LC schreibt, statt die kurze übersichtliche for-Variante. Und da du die Daten bereits direkt verarbeitest, möchtest du eigentlich auch keine LC benutzen, sonderen einen Generatorausdruck.

Jetzt kannst du vielleicht auch wieder einschlafen ^^
Das Leben ist wie ein Tennisball.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

EyDu hat geschrieben:Zum Beispiel sind die Klammern um das "result" überflüssig.
Das wusste ich so nicht, hätte ich mir aber auch denken können...
EyDu hat geschrieben:"result" ist außerdem unpassend, da es gar nicht das Ergebnis ist.
War ich auch nicht glücklich damit, aber mangels Alternativen hab' ich's einfach gelassen... :wink:
EyDu hat geschrieben:Dann könnte man sich noch fragen, warum du einen String zurück gibst und nicht das das Tupel, denn normalerweise möchte man mit den Daten arbeiten und sie nicht ausgeben. Vielleicht möchte man einfach die ganze LC als Ergebnis der Funktion verwenden.
Da hast Du schon Recht, allerdings wollte ich das bereits vorhandene Beispiel in seiner Struktur nicht völlig verändern.
EyDu hat geschrieben:Dann stellt man sich natürlich noch die Frage, warum man, wenn die Daten schon gleich verarbeitet werden, einen ellenlange unübersichtliche LC schreibt, statt die kurze übersichtliche for-Variante.
Na ja, die Frage stelle ich mir ja auch. Ich habe einfach nur "zur Übung" versucht, die for-if Konstellation in ein LC zu packen. Über den Sinn kann man natürlich streiten. Unstrittig ist allerdings, dass die LC schneller ist... ups, jetzt isch's raus...
EyDu hat geschrieben:Und da du die Daten bereits direkt verarbeitest, möchtest du eigentlich auch keine LC benutzen, sonderen einen Generatorausdruck.
Aber über den Generator müsste ich ja dann nochmals iterieren, oder? Wäre das dann nicht doppelt gemobbelt?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Was meinst Du mit "nochmals iterieren"? Im Moment erstellst Du eine Liste und iterierst über die. Wenn Du statt der Liste dort einen Generatorausdruck stehen hast, dann iterierst Du halt darüber statt über die Liste. Das ist eher weniger "doppelt gemobbelt", weil die Schleife, die implizit in der LC steckt, dann weg fällt.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Also es ist ja nicht so, dass ich nicht wirklich versuche, das zu verstehen. Nur: Ich versteh's nicht!
Wo liegt der Unterschied zwischen

Code: Alles auswählen

for element in ['\t%s\t%s' % entry 
    for entry in directory.iteritems()
    if any(searchstring.lower() in item.lower() 
    for item in entry)]:
    print element
und

Code: Alles auswählen

for element in ('\t%s\t%s' % entry 
    for entry in directory.iteritems()
    if any(searchstring.lower() in item.lower() 
    for item in entry)):
    print element
Ok, das mit doppelt gemobbelt nehm' ich zurück. Aber wo spar' ich mir mit der Generatorlösung eine Schleife?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Naja, mit einem Generatorausdruck, erzeugst du ein Generator, spricht der wird noch nicht sofort ausgeführt, sondern erst wenn über ihn iteriert wird. Wenn du eine Liste erstellts, muss diese erst erzeugt werden und dann kannst du erst darüber iterieren.

Edit: Achso eine kleine Schwachstelle seh ich da noch, wenn deine Daten in der Dictionary nun dochmal keine Strings sind, bekommst du noch ein kleines Problem mit ".lower()", eventuell also nochmal Typumwandlung zu string.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Xynon1 hat geschrieben:Naja, mit einem Generatorausdruck, erzeugst du ein Generator, ...
Soweit ist mir das schon klar. Ich hatte BlackJack allerdings dahingehend verstanden,
BlackJack hat geschrieben:... weil die Schleife, die implizit in der LC steckt, dann weg fällt.
dass ich mir beim Generator im Gegensatz zur LC eine Schleife spare. Und ich kann nicht sehen, wo bzw. wie...
Xynon1 hat geschrieben:... wenn deine Daten in der Dictionary nun dochmal keine Strings sind, ...
Hmm, entweder oder. Oder? Ich finde halt, dass spätestens in der Suchroutine feststehen sollte, um welchen Typ es sich handelt. Die Festlegung bzw. Umwandlung gehört meiner Ansicht nach an eine andere Stelle.
Xynon1 hat geschrieben:... bekommst du noch ein kleines Problem mit ".lower()", ...
Genaugenommen gehört auch ein .lower() nicht unbedingt in die Suchfunktion.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

mutetella hat geschrieben:
BlackJack hat geschrieben:... weil die Schleife, die implizit in der LC steckt, dann weg fällt.
dass ich mir beim Generator im Gegensatz zur LC eine Schleife spare. Und ich kann nicht sehen, wo bzw. wie...
Der Unterschied ist folgender: In der LC fuehrst du die gesamte Schleife auf einmal aus, um an die Liste zu kommen, dann iterierst du ueber die Liste. Mit der GE erzeugst du immer nur ein Element und fuehrst die Schleife nicht dort aus, sondern in der aeusseren Iteration.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Puh.... da muss ich nochmal nachhaken, das versteh' ich so noch nicht!
Cofi hat geschrieben:... und fuehrst die Schleife nicht dort aus, sondern in der aeusseren Iteration.
Besteht der Unterschied zwischen LC und Generator letztlich nicht darin, dass eine LC die enthaltenen Schleifen sofort durchläuft und eine Liste zurückgibt, wohingegen ein Generator dieselben Schleifen durchläuft, allerdings nach jedem Durchgang das Ergebnis zurückgibt, den Prozess anhält und wartet, bis ein erneuter Durchgang/ein erneutes Ergebnis angefordert wird (in unserem Fall durch die äußere Iteration)?
Wenn ich damit nicht falsch liege führt doch der Generator dieselbe Anzahl an Schleifen aus, nur eben nicht fortlaufend, sondern quasi "stotternd".

Bitte nicht falsch verstehen! Ich möchte hier keine Haarspalterei betreiben, aber solche Details sind für mein Verständnis wichtig!

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

"stotternd" - ist gut :D
Was den Vorteil betrifft, sollte dir klar sein - Geschwindigkeit und weniger Speicherverbrauch.

Überlege mal warum man "range" (in Python < 3.x) nicht für einfache Iteration nutzen sollte. Gutes Beispiel hier: http://www.python-forum.de/viewtopic.ph ... 86#p185486
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@mutetella: So gesehen stimmt das natürlich, das auch im Generatorausdruck noch eine Schleife läuft. Da die aber im "Glecihschritt" mit der äusseren Schleife "läuft", also immer wenn die äussere einen Durchlauf macht, dann tut das auch die innere, wird damit von meiner Sichtweise her die Generatorschleife zu einem Teil der äusseren.
Antworten