Python / Problem: Die Katze beißt sich in den Schwanz

avatar

Ich bin seit einiger Zeit dabei ein Programm zu schreiben/versuchen, welches das Ablaufdatum von Lebensmitteln dokumentiert, bzw. Verbrauchte aus der Liste löschen lässt. Und natürlich sollte man auch nach Begriffen suchen können

Dabei wird primär ein Dictonary verwendet, welches das Datum als Schlüssel speichert, und die Lebensmittel dann als Liste. Das ganze wird von einer json-Datei ein und ausgelesen. Derzeit, wie alles bei mir, noch ein Konsolenmodell.

Aktuell scheitere ich sozusagen an einer ziemlich einfachen Aufgabe. Eigentlich schreibe ich hier, um vielleicht durch die Beschreibung des Problems selbst auf einen Lösungsansatz zu kommen. Das Problem selbst zu beschreiben fällt mir schon schwer, die Überschrift passt aber ziemlich gut dazu, finde ich.

Also, mein Wunsch ist es, jeden Eintrag als Nummer zu versehen, damit man beim Löschen (wie gesagt, das Programm funktioniert nicht mit der Maus, das kann ich noch nicht), nur eine Zahl eintippen und Enter drücken muss. Entspechend muss jeder Eintrag immer um 1 höher als der vorherige sein. Klingt leicht, ist es aber für mich nicht, denn das Programm merkt sich nichts, für das nächste Mal. Naheliegend könnte man sagen, die Speicherung in die Datei könnte an anderer Stelle erfolgen, jedoch war es ein ewig langes Herumprobieren, um die Position von "open with..." zu finden. Da hatte ich das Problem ExtraData, was bedeutet. die json-Datei hat am Anfang immer wieder unsinnige Klammern eingebaut {}.

Wenn ich jetzt die Struktur überlege, hätte ich die Möglichkeit einer for-Schleife. for nummer in range(übergebene_zahl, 999999), obwohl mir das etwas unprofessionell aussieht (soweit ich mich trauen kann, das überhaupt zu sagen)
Die übergebene Zahl wäre quasi die, welche beim beenden des Programms gespeichert wird. Oder nachdem es eine Endlosschleife mit User-Abbruch ist, nummer=0, nummer+=1. .. Nein, kann man vergessen. Dann initialisiert sich nummer sowieso immer mit 0. Wie kann ich das besser verdeutlich?

Die Information welche Nummer letztlich am Ende der Benutzung feststeht, kann erst gesetzt werden, wenn der Benutzer alle Einträge gemacht hat. Bsp. {"01.09.2023":[1. "Apfel", 2. "Birne", 3. "Milch"}]. Die übergebene_Zahl muss aber irgendwie an den Anfang des Codes kommen, denn ansonsten wird es ein NameError, weil die Zahl noch nicht existiert (Die Katze beißt...). Das frustriert mich gerade etwas, denn das sieht leicht zu lösen aus. Ich bin mir auch sicher, wenn ich die Lösung gefunden habe, oder jemand hier den richtigen Ansatz zeigt, dass ich mir dann aufs Hirn klatsche.

Ahja, dass ich während des Schreibens selbst auf die Lösung komme, ist leider nicht passiert.

import json

user_choice=input("""                      Verwenden Sie 1, um einen Eintrag hinzu zu fügen: 
                      Verwenden Sie 2, um nach einem Eintrag zu suchen:
                      Verwenden Sie 3, um sich die Liste anzeigen zu lassen:
                      Verwenden Sie 4, um verbrauchte Lebensmittel aus der Liste zu löschen:    
                  
                      Ihre Wahl: """)

if user_choice == "1":
    lebensmittel_dict = {}
    try:
        with open("Lebensmittel.json", 'r') as json_file:
            lebensmittel_dict = json.load(json_file)
    except FileNotFoundError:
        pass

    while True:                        
        lebensmittel_liste=[]
        user_datum = input("Datum? ")
        if user_datum in lebensmittel_dict:
            print("In diesem Datum stehen bereits Lebensmittel")
            lebensmittel_liste=lebensmittel_dict.get(user_datum)
        user_lebensmittel = input("Firma, Produkt? ")
        lebensmittel_liste.append(user_lebensmittel)        
        lebensmittel_dict[user_datum] = lebensmittel_liste
        user_input = input("Einen weiteren Eintrag hinzufügen j/n ")
        if user_input == "n":
            break
        
    with open("Lebensmittel.json", 'w') as json_file:
        json.dump(lebensmittel_dict, json_file, indent=4, sort_keys=True)
    print("Einträge aus Datei:", lebensmittel_dict)

elif user_choice=="2":
    user_input=input("Geben Sie ein Datum, oder einen Suchbegriff ein: ")        
    with open("Lebensmittel.json", 'r') as json_file:
        lebensmittel_dict = json.load(json_file)
    for key, value in lebensmittel_dict.items():
        if user_input in key or user_input in value:
            print("Gefundener Eintrag - Schlüssel:", key, "Wert:", value)
        #else:
          #  print("Suchbegriff leider nicht gefunden.")
elif user_choice=="3":
    with open("Lebensmittel.json", 'r') as json_file:
        lebensmittel_dict = json.load(json_file)
    for x in lebensmittel_dict.items():
        print(x)

elif user_choice=="4":
    print ("Welche Daten sollen gelöscht werden. Sie können einfach die Nummer auswählen: ")
    with open("Lebensmittel.json", 'r') as json_file:
        lebensmittel_dict = json.load(json_file)
    for x in lebensmittel_dict.items():
        print(x)
else:
    print("Ihre Eingabe ist ungültig")



0
0
0.000
11 comments
avatar

Hoffentlich kann dir dabei jemand helfen!

Schreib doch mal die üblichen Verdächtigen hier direkt nach Hilfe an.

LG
Sascha

0
0
0.000
avatar

!PIZZA

0
0
0.000
avatar

Ich weiss nicht, ob ich das Richtig verstanden habe mit der Nummer zum löschen eines Eintrages. Hier mal ein Fragment wie man eine Nummer eingeben kann um ein Eintrag aus dem dictionary zu löschen. Die Nummern werden jedesmal beim ausführen der Anwendung neu vergeben. Es muss nichts gespeichert werden, außer das veränderte Dictionary als JSON.

# Struktur der JSON Datei falls ich es richtig verstanden habe
jsondata = {"01.01.2000" : ["Apfel", "Birne"], "02.01.2000" : ["Eisen", "Honig"]}

# Während dieser Anwendung
application_data = {}

class Lebensmittel:

    def __init__(self, id, date, productname):
        self.date = date # Ablaufdatum
        self.id = id # eindeutige Nummer wird vergeben, während des Einlesens der JSON-Datei
        self.prodcutname = productname # Lebensmittelname

    def getNumber(self):
        return self.id # Lebensmittel mit der eingegebenen Zahl wird ermittelt

    def __repr__(self):
        return f'{self.id, self.prodcutname}'

def deleteWithNumber(number):
    entryToRemove = None
    for values in application_data.values():
        actualEntry = values
        for elem in actualEntry:
            # Suche nach der eingegebenen Nummer
            if elem.getNumber() == number:
                entryToRemove = elem
                break
        break
    if entryToRemove is not None:
        application_data[entryToRemove.date].remove(entryToRemove)


if __name__ == '__main__':
    id = 1 # erhöhe um 1 in der inneren Schleife, pro Lebensmittel. Kein speichern nötig.
    for key, value in jsondata.items():
        entries_with_numbers = []
        for entry in value:
            entries_with_numbers.append(Lebensmittel(id, key, entry))
            id += 1
        application_data.update({key: entries_with_numbers})

    # Vorher
    for k, v in application_data.items():
        print(k, v)

    deleteWithNumber(2) # Beispiel: Lebensmittel mit der Nummer 2 wird gelöscht

    # Nachher
    for k, v in application_data.items():
        print(k, v)
0
0
0.000
avatar

Danke Ozelot; ich kann gar nicht sagen ob das stimmt was du schreibst. Ich bin mit dem Bereich der Klassen noch sehr wenig vertraut.

Der Mechanismus soll quasi einen Integer (beginnend mit 0 oder 1) immer +1 erhöhen, wenn der User ein Nahrugsmittel eingibt. Problem ist bei mir, dass ich es nur schaffe, innerhalb einer Session diese Nummern hochzuschieben. Beim nächsten Start habe ich quasi einen reset.

0
0
0.000
avatar

Ah, so meinst du das mit der Nummer. Das beste wäre, wenn du in dieser JSON-Datei die du für die Lebensmittel hast diese Nummer separat mit abspeicherst. Wenn du in der Anwendung dann ein neues Nahrungsmittel hinzufügst, erhöhst du die Zahl um 1. Beim speichern der JSON-Datei überschreibst du den vorher eingelesenen Wert, hier im Beispiel counter, mit dem neuen Wert. Und beim nächsten einlesen der JSON-Datei hast du dann die letzte Zahl die du in der letzten Sesson verwendet hast.

Zum Beispiel so hier:

{
    "counter" : 0,
    [
        {
            "ablaufdatum" : "01.01.2000",
            "produkt" : "Apfel"
        },
        {
            "ablaufdatum" : "01.01.2000",
            "produkt" : "Birne"
        },
        {
            "ablaufdatum" : "05.01.2000",
            "produkt" : "Pflaume"
        },
        {
            "ablaufdatum" : "05.01.2000",
            "produkt" : "Zitrone"
        }
    ]
}
0
0
0.000
avatar
(Edited)

also, ich habe sogar eine separate json Datei. Wobei mir manchmal der Mechanismus fremdartig vorkommt. (Ich schaffe es nicht, ohne expecting Value, oder ExtraData auszukommen, wenn ich keine Try except pass vorne hinstelle). Muss offenbar noch einige Dinge stärker für mich runterbrechen.

Hast du gmeint, ich soll den Counter bereits im Vorfeld in die Json Datei schreiben?
(also nicht durch einen Pyton Code)

Und ja, das wollte ich, (die Nummer in Json Code abspeichern), aber aus welchem Grund auch immer schaffe ich das nicht vernünftig. (Aber vielleicht eh, weil sie eben im Vorfeld noch nicht in der JSon Datei existiert hat.)

sry, falls das wirr klingt.


Nachtrag:

...
{ "counter" : 0,
"01.09.2023": [
"aaa",
"bbb"
],
"02.09.2023": [
"ccc",
"ddd"
]
}
...

Mir ist nicht klar, wie ich auf diesen Counter zugreifen kann in Python. Er existiert ja quasi im Code noch nicht.

0
0
0.000
avatar
(Edited)

Genau, den counter vorher schon in die JSON-Datei schreiben. Für den counter legst du in python eine Variable an, die mit dem counterwert aus der JSON-Datei überschrieben wird.

Um an den counter zu kommen, überprüfst du, ob es in der JSON-Datei ein key mit dem Namen counter gibt. Wenn das der Fall ist, dann kannst du den value zu diesem key einlesen.

import json

# habe ich jetzt mal als string geschrieben.
jsondata = '''{ "counter" : 0,
"lebensmittel" : {
"01.09.2023": [
"aaa",
"bbb"
],
"02.09.2023": [
"ccc",
"ddd"
]
}
}'''

# variable die den counter speichert, der aber noch initialisiert werden muss
my_counter = None
my_lebensmittel = None

# parse den string/datei und erhalte das root-Element
rootElement = json.loads(jsondata)

# prüfe, ob der key mit dem Namen 'counter' existiert
if 'counter' in rootElement:
    my_counter = rootElement['counter']
else:
    raise ValueError('counter nicht gefunden')
print(my_counter)

# prüfe nun ob es den key 'lebensmittel' gibt
if 'lebensmittel' in rootElement:
    my_lebensmittel = rootElement['lebensmittel']
else:
    raise ValueError('lebensmittel nicht gefunden')

# lebensmittel dictionary
for k, v in my_lebensmittel.items():
    print(f'{k} -> {v}')

Edit Ich habe die JSON ein bisschen abgeändert, damit du neben den counter auch die Lebensmittel direkt als dictionary einlesen kannst. Dazu habe ich die Lebensmittel mit dem key "lebensmittel" verschachtelt um diese direkt als dictionary in my_lebensmittel speichern zu können. Ohne diesen neuen Key müsstest du die einzelnen Tage kennen die immer unterschiedlich sein können, also 01.09 als key, 02.09 als key usw.

0
0
0.000
avatar

Vielen Dank, ozelot.
Tatsächlich ignoriere ich leider viel zu häufig die Nützlichkeit von None.
Derzeit versuche ich wieder ein wenig zu wiederholen. Schrecklich, was da im Laufe der Zeit verloren geht, auch wenn man denk, man hätte alles irgendwie in Verwendung.

Ich probier das aus und geb dir dann Bescheid.

0
0
0.000