Suche mittels Schleife in einer 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
Bisler
User
Beiträge: 4
Registriert: Mittwoch 5. Mai 2021, 10:44

Guten Tag zusammen

Ich habe eine Liste mit Angaben von Personen erstellt. In diesen habe ich diverse Angaben befüllt. Die Listen für die Mitarbeiter, je eine pro Mitarbeiter, habe ich in einer Gesamtliste (MA) zusammengefasst.

Code: Alles auswählen

ma1 = ['Muster', 'Max',  123], ma2 = ['Heinzmann', 'Karl', 456],  ma3 = ['Steffen', 'Ute', 789]

Code: Alles auswählen

ma = ['ma1', 'ma2', 'ma3']
Mit tkinter habe ich eine Oberfläche erstellt, sowie eine Entry in welcher der User den Namen der Person eingeben kann. Da ich in bei einer Namenssuche der Mitarbeiter die Namen ausgeben will, habe ich eine While-Schleife erstellt. Diese Funktion (def enter()) habe ich mit einem Button verbunden.

Code: Alles auswählen


def enter():

    x = 0
    y = 0

    try:
        while entry.get().capitalize() != ma[x][y]:
            x += 1
        else:
            leer_label =Label(root)
            leer_label.grid(row=4, column=4)
            result_label = Label(root, text=(ma[x][y]) + " " + (str(ma[x][1])))
            result_label.grid(row=5, column=0)
            result_label = Label(root, text=str(ma[x][2]))
            result_label.grid(row=5, column=1)

    except: messagebox.showerror('Fehler', 'Suche muss über den Familiennamen erfolgen!')
Nun wird mir bei einer Namenssuche die dritte Stelle in der Liste (Zahl) ausgegeben. Das funktioniert nicht schlecht nur gibt es ein grosses Problem. Viele Personen tragen denselben Familiennamen.
Zudem überschreibt sich dauernd das Label, was aufgrund der While-Schleife ja logisch ist, jedoch habe ich auch dort keine optimale Lösung gefunden.

Ich wäre froh um einen guten Input, da ich momentan schon recht lange an dem Thema herumbastle. :shock:

Vielen Dank für die Unterstützung.

:geek:
:geek:
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze keine kryptischen Abkürzungen. Warum schreibst Du nicht `mitarbeiter` statt ma?
Alles was eine Funktion braucht, muss sie über ihre Argumente bekommen. `enter` braucht also entry, ma und root.

Eine GUI wird einmal aufgebaut und dann nur noch der Inhalt der Labels geändert. So wie jetzt packst Du immer mehr Labels übereinander.

Wenn eine while-Schleife kein break hat, ist ein else-Block unsinn, weil der else-Block immer betreten wird und jeder vergeblich das break sucht.
Mit x und y verbindet man Kommazahlen, keine Indizes. Statt mit Indizes arbeitet man in Python auch direkt mit den Elementen der Liste und statt while mit for.
Nackte except behindern die Fehlersuche. Fange immer Fehler so konkret wie möglich ab. Hier würde man das gar nicht mit einer Exception lösen, sondern bei keiner Übereinstimmung einfach diesen Fall per if abfragen.

Statt in einer Liste verschiedene Eigenschaften zu sammeln benutzt man komplexere Datenstrukturen. Hier böte sich ein namedtuple für den Typ eines Mitarbeiters an.

Was soll passieren, wenn mehrere Treffer gefunden werde? Das kann man ja in der Oberfläche verschieden lösen: Auswahlliste, Datensatzweiter-Knopf, etc.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Das `enter` könnte ungefähr so aussehen:

Code: Alles auswählen

from collections import namedtuple

Employee = namedtuple("Mitarbeiter", "surname, forename, age")

def enter(employees, search_field, result_name, result_age):
    name = search_field.get().capitalize()
    for employee in employees:
        if name == employee.surname:
            break
    else:
        messagebox.showerror('Fehler', 'Suche muss über den Familiennamen erfolgen!')

    result_name['text'] = f"{employee.surname} {employee.forename}"
    result_age['text'] = employee.age


def initialize():
    ...        
    employees = [
        Employee('Muster', 'Max',  123),
        Employee('Heinzmann', 'Karl', 456),
        Employee('Steffen', 'Ute', 789),
    ]
    ...
    result_name = tk.Label(root)
    result_name.grid(row=5, column=0)
    result_age = tk.Label(root)
    result_age.grid(row=5, column=1)
    ...
Das was in `initialize` steht, mußt Du natürlich in Deinem Code entsprechend einbauen.
Bisler
User
Beiträge: 4
Registriert: Mittwoch 5. Mai 2021, 10:44

Guten Morgen Sirius3

Vielen Dank für deine Antworten. Ich sehe, dass ich hier einen völlig falschen Ansatz getroffen habe und mich danach immer tiefer in den Fehler oder die Fehler manövriert habe. Nun werde ich die ganze Angelegenheit neu aufbauen und Deinen Hilfeleistungen folgen. :)

Grüsse
Bisler
:geek:
Bisler
User
Beiträge: 4
Registriert: Mittwoch 5. Mai 2021, 10:44

Guten Tag zusammen

Ich habe mir nochmals einige Gedanken zum Thema gemacht und danach entschieden die Informationen, welche ich für die Ausgabe benutze statt aus einem Namedtuple aus einer SQL-Datenbank zu holen. Mir fällt es einfach leichter die neuen Werte ein, auszugeben oder zu verändern wenn diese in einer Datenbank gespeichert sind.

Sirius3 hat mir mit seiner Hilfestellung jedoch sehr geholfen und so habe ich meine Suchfunktion angepasst. Da bei uns viele Mitarbeiter denselben Familiennamen tragen, habe ich die Suche nun auf Familien- und Vornamen ausgedehnt.

Nun habe ich eine Eingabemaske aufgebaut mit Tkinter mit zwei Entrys (Familienname und Vorname). Mit einer Suchfunktion, die an einen Button gebunden wurde, wird nun die Eingabe in der Datenbank überprüft und in einem Ausgabefenster präsentiert. Da das kopieren auf den Labels nicht funktioniert, habe ich einfach die Ausgabe in eine Entry gelegt. Die Entry habe ich mit der Farbe und dem relief=FLAT angepasst. Nun ist das Resultat für den User kopierbar. :D Nun, es ist mir bewusst, dass noch nicht alles perfekt ist, aber ich werde weitere Anpassungen vornehmen und falls Ihr noch Anweisungen, Ideen habt, bin ich natürlich sehr dankbar. Gerne werde ich euch bei Interesse auch die anderen Codes posten :D

Code: Alles auswählen

def search():

#Aufrufen der Datenbank
    conn = sqlite3.connect('meine_Datenbank.db')
    c = conn.cursor()

#Suche in der Datenbank nach den versch. Inhalten. Die oid lasse ich mir ausgeben, weil ich diese in einer anderen Funktion benutze um Daten aus der Datenbank zu löschen
    c.execute("SELECT *, oid FROM mitarbeiter")
    inhalt = c.fetchall()

    #Eingabe von Familienname und Vornamen
    for i in inhalt:
        if i[0] == famname_entry.get() and i[1] == forename_entry.get():
            ausgabe = Entry(top, text="", width= 30, relief=FLAT, bg="white",font=('Helvetica', 16))
           ausgabe.insert(0, i)
           ausgabe.pack()
           break


    conn.commit()
    conn.close()
:geek:
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Globale Variablen benutzt man nicht. top, famname_entry und forename_entry müssen Argumente von `search` sein.
Variablennamen müssen aussagekräftig sein, einbuchstabige Namen sind das nie. `c` -> cursor, i -> mitarbeiter. Für `inhalt` würde ich auch einen besseren Namen wählen, der mehr über den Inhalt aussagt.
Benutze keine *-SELECTS, sondern gebe die Felder explizit an. Statt oid solltest Du eine explizite Mitarbeiter-ID anlegen. Datenbanken sind dazu da, dass man Daten sucht, nicht dass Du das in Python nachprogrammierst. Beim SELECT fehlt also noch ein WHERE mit Vor- und Nachname.
Man erzeugt nachträglich keine Entries, sondern setzt nur deren Inhalt.

Code: Alles auswählen

def search(ausgabe, familyname_entry, forename_entry):
    connection = sqlite3.connect('meine_Datenbank.db')
    cursor = connection.cursor()

    cursor.execute("SELECT mitarbeiter_id, familienname, vorname FROM mitarbeiter WHERE familienname=? AND vorname=?",
        [familyname_entry.get(), forename_entry.get()])
    mitarbeiter = cursor.fetchone() # was tun bei mehreren Einträgen?
    ausgabe.insert(0, mitarbeiter)
    ausgabe.pack()
    cursor.close()
    connection.close()
Bisler
User
Beiträge: 4
Registriert: Mittwoch 5. Mai 2021, 10:44

Vielen Dank Sirius3
Ich werde mich gleich daransetzen und die Einträge korrigieren und dass ganze Programm nochmals durchschauen. Das mit der oid habe ich mir von einem Amerikaner abgeschaut.
Werde mal versuchen Mitarbeiter_ID zu erstellen. In der Firma hat jeder eigentlich eine, von dem her würde sich das direkt anbieten, wenn ich diese so übernehme.
:geek:
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bisler: Ich verwende fast immer künstliche IDs. IDs sind ja für Fremdschlüssel und dürfen sich nicht ändern. Und es ist erstaunlich was für reale unveränderliche IDs sich dann *doch* irgendwann einmal ändern. Man glaubt gar nicht wie viele DB-Entwürfe mal davon ausgegangen sind, das deutsche Postleitzahlen immer vierstellig waren und immer vierstellig sein werden. Und dann kam überraschend die Wende und plötzlich waren sie fünfstellig.

Mitarbeiter-IDs ändern sich beispielsweise gerne mal bei Firmenübernahmen oder Fusionen, oder wenn die Software zur Personalverwaltung durch eine andere ausgetauscht wird.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten