Seite 1 von 1

Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 07:44
von Jankie
Hey,

ich möchte eine Art Telefonbuch erstellen.

Wenn ich ein Teil vom Namen schreibe, soll er mir alle ähnlichen Namen ausgeben.
Bsp.:

Code: Alles auswählen

contacts = {"Jens Follmann" : 123, "Hans Bauer" : 456, "Karl Heinz" : 789, "Theo Schmidt" : 122, "Tim Schmitt" : 133, "Gustav Weber" : 144}
Wenn ich "Schm" eingebe soll er mir ausgeben:

Theo Schmidt 122
Tim Schmitt 133

oder wenn ich "Ba" eingebe soll er mir:

Hans Bauer 456

ausgeben.

Das ganze soll wenn möglich nur mit Modulen aus der Standartbibliothek umgesetzt werden. Ich habe schon mal bisschen gesucht und difflib gefunden, speziell die Funktion get_close_matches. Allerdings liefert mir das nur ungenaue Ergebnisse.

Mein Code:

Code: Alles auswählen

from difflib import get_close_matches
contacts = {"Jens Follmann" : 123, "Hans Bauer" : 456, "Karl Heinz" : 789, "Theo Schmidt" : 122, "Tim Schmitt" : 133, "Gustav Weber" : 144}
similar_names = get_close_matches(input("Bitte Name eingeben: "), contacts.keys(), n = 10)
for name in similar_names:
    print(f"{name} {contacts[name]}")
Wenn ich jetzt bspw. die Nummer von Theo Schmidt haben möchte und "Schm" eingebe, kommt nichts. Wenn ich "Schmi" eingebe, kommt Tim Schmitt. Wenn ich "Theo" eingebe kommt auch nichts.

Ich hoffe ich habe mein Problem verständlich rüberbracht und wäre für Hilfe dankbar.

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 08:03
von Jankie
Okay, ich glaube ich habe es hinbekommen.

Code: Alles auswählen

contacts = {"Jens Follmann" : 123, "Hans Bauer" : 456, "Karl Heinz" : 789, "Theo Schmidt" : 122, "Tim Schmitt" : 133, "Gustav Weber" : 144}
names = list(contacts.keys())
name_to_search = input("Name: ")

for x in range(0, len(names)):
    if name_to_search in names[x]:
        print(f"{names[x]} {contacts[names[x]]}")
Name: Ha
Hans Bauer 456


Name: F
Jens Follmann 123


Name: Sc
Theo Schmidt 122
Tim Schmitt 133

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 08:03
von __deets__
Wenn es nicht um Trigramme und Levensthein-Abstände geht (mit denen man mit scm auch Schmitt findet), dann reicht ein simples

if needle in haystack:

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 08:05
von __deets__
Nachtrag: haste ja selbst gefunden. Fein. Jetzt nur noch ganz schnell sich abgewöhnen, auf Listen mit Index zuzugreifen. Das macht man in Python nicht.

Code: Alles auswählen

for name in names: 
      print(name)

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 08:15
von Jankie
Hm, ich wüsste gerade nicht wie ich das ohne auf den Index zuzugreifen lösen könnte. Kannst du mir bitte ein kurzes Snippet zeigen, indem der Unterschied klar wird? Und warum macht man das eigentlich nicht?

Noch eine kurze Frage:

wie bekomme ich die Ausgabe so formatiert, dass die Zahlen alle untereinander stellen, slo statt

Code: Alles auswählen

Name: e
Jens Follmann 123
Hans Bauer 456
Karl Heinz 789
Theo Schmidt 122
Gustav Weber 144
das so darstellen:

Code: Alles auswählen

Name: e
Jens Follmann  123
Hans Bauer     456
Karl Heinz     789
Theo Schmidt   122
Gustav Weber   144

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 08:30
von __deets__
Ich habe dir doch ein snippet gemacht. Und überall wo du jetzt ein Knödeliges “names[x]” stehen hast, kannst du damit einfach “name” benutzen. Und das ist auch ein Grund, warum das besser ist. Weil es weniger Schreibarbeit ist. Andere sind, dass diese Konstrukt (for ding in dinge) auch funktioniert, wenn man NICHT wahlfrei zugreifen kann. Zb bei Zeilen in Dateien.

Für eine solche tabellarische Ausgabe musst du den längsten Namen bestimmen, und daraus dann das notwendige padding berechnen.

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 08:55
von Jankie
Habe es hinbekommen, danke für die Hilfe.

Code: Alles auswählen

contacts = {"Jens Follmann" : 123, "Hans Bauer" : 456, "Karl Heinz" : 789, "Theo Schmidt" : 122, "Tim Schmitt" : 133, "Gustav Weber" : 144}
names = list(contacts.keys())
name_to_search = input("Name: ")
for name in names:
    if name_to_search in name.lower():
        print(f"{name:<15} {contacts[name]}")
Ausgabe:

Code: Alles auswählen

Name: e
Jens Follmann   123
Hans Bauer      456
Karl Heinz      789
Theo Schmidt    122
Gustav Weber    144

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 09:14
von nezzcarth
Jankie hat geschrieben: Mittwoch 5. Juni 2019, 07:44 Das ganze soll wenn möglich nur mit Modulen aus der Standartbibliothek umgesetzt werden.
Wenn das nur für private Zwecke zum Lernen gedacht ist, ist das okay. An sich gibt es aber deutlich bessere Verfahren, gerade auch zur Namenssuche. Da sollte man dann aber auf externe Bibliotheken zugreifen. (Gerade die von __deets__ erwähnte Levenshteindistanz würde ich nicht selbst implementieren, sondern nach Möglichkeit eine der Implementierungen in C/C++ nehmen, für die einen der verbesserten Algorithmen -- also nicht den üblicherweise erklärten Dynamic Programming Algorithmus .)

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 09:29
von __deets__
Jankie hat geschrieben: Mittwoch 5. Juni 2019, 08:55

Code: Alles auswählen

print(f"{name:<15} {contacts[name]}")
Hmja. Das ist natuerlich nicht so super, denn wenn ein neuer Name dazu kommt, der laenger ist, ist essig. Da solltest du besser die Laenge dynamisch bestimmen, und dann benutzen. Das wird ein bisschen fummelig, weil man dann entweder einen format-string formatieren muss, oder einfach die Namen selbst padded.

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 10:02
von __blackjack__
@Jankie: Zwischen Schlüssel und Doppelpunkt wird üblicherweise *kein* Leerzeichen gesetzt.

Bei `names` ist der `list()`-Aufruf überflüssig. `names` an sich ist auch überflüssig, man muss nicht jedes Zwischenergebnis an einen Namen binden. Und wenn man letztlich Schlüssel und Wert braucht, kann man auch gleich über `items()` iterieren.

Die 15, beziehungsweise die konkrete Länge sollte man besser aus den Namen ermitteln, damit das auch noch passt wenn jemand mit einem deutlich längeren Namen in den Kontaktdaten vorkommt.

Ein Wörterbuch ist nicht unbedingt die erforderliche Datenstruktur wenn man über alle Einträge iteriert und nicht über Schlüssel auf Werte zugreifen will.

Das Vor- und Nachname in einer Zeichenkette stecken, macht das übliche sortieren nach Nachnamen schwierig bis unmöglich.

Telefonnummern sind keine Zahlen. Wobei es ja nur „so eine Art Telefonbuch“ sein soll, und Du nichts über die Bedeutung der Nummern gesagt hast, wollte ich das trotzdem mal anmerken.

@__deets__: So fummelig wird das gar nicht, man kann Platzhalter verschachteln.

Code: Alles auswählen

#!/usr/bin/env python3


def main():
    contacts = {
        'Gustav Weber': 144,
        'Hans Bauer': 456,
        'Jens Follmann': 123,
        'Karl Heinz': 789,
        'Theo Schmidt': 122,
        'Tim Schmitt': 133,
    }
    name_to_search = input('Name: ').lower()
    max_name_length = max(map(len, contacts))
    for name, number in contacts.items():
        if name_to_search in name.lower():
            print(f'{name:<{max_name_length}} {number}')


if __name__ == '__main__':
    main()

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 10:04
von __deets__
Oha, neat.

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 10:22
von Sirius3
@Jankie: die Variable `names` ist überflüssig, weil die Namen ja schon in contacts stehen. Wenn Du in Kleinbuchstaben vergleichst, solltest Du auch den Suchstring umwandeln. Wenn Du die Telefonnummer benutzen willst, iteriere gleich über Schlüssel und Wert.

Code: Alles auswählen

contacts = {"Jens Follmann" : 123, "Hans Bauer" : 456, "Karl Heinz" : 789, "Theo Schmidt" : 122, "Tim Schmitt" : 133, "Gustav Weber" : 144}
name_to_search = input("Name: ").lower()

for name, number in contacts.items():
    if name_to_search in name.lower():
        print(f"name} {number}")
@__deets__: was soll an Formatstring-Formatierungen fummelig sein?

Code: Alles auswählen

f"{name:<{width}} {number}"
Zudem: alles ist besser als selbst padden.

Re: Ähnlichen String ausgeben

Verfasst: Mittwoch 5. Juni 2019, 10:42
von Jankie
@__blackjack__:

Das list() hatte ich noch drin, da ich meine erste Version (zweiter Post) immer nur angepasst habe und dort der list aufruf nötig war um über den Index zuzugreifen.
Der Code wird eigentlich nur von mir genutzt, um unsere interne Telefonliste zu vereinfachen, da wir nur eine unübersichtliche Excel-Liste haben und da das suchen manchmal nervig sein kann. (ja ich weiß mit Strg + F kann man auch in Excel suchen aber so gefällt es mir besser) es sind auch keine "richtigen" Telefonnummern, sondern nur Durchwahlnummern. Und sortiert muss es für meine Verwendung nicht sein.

Das mit der 15 war bisschen schlecht von mir gelöst, stimmt. Auch dir danke für die Hilfe und die "Musterlösung".