<jupyter_start><jupyter_text>3.5 Dictionaries 3.5.4 Die wichtigsten Dictionary-FunktionenIm Anschluss dieser Übungseinheit kannst du ...+ Dictionarys und Subdictionarys auf verschiedene Weisen updaten+ Einträge (Key-Value-Paare) in Dictionarys und Subdictionarys auf verschiedene Weisen löschen+ Dictionarys und Subdictionarys auf verschiedene Weisen löschen+ Dictionarys flach und tief kopieren+ die Anzahl der Einträge eines Dictionarys feststellen+ ein Dictionary in einen String umwandeln     Hinweis zur Bearbeitung dieser Einheit (Erinnerung):      Du wirst im Laufe dieser Einheit wieder Fragen sowie kleine Aufgaben lesen. Du erkennst sie an ihrer Farbgebung in orange. Überlege dir erst eine Antwort und probier sie aus, bevor du zu der weiter darunterliegenden Code-Zelle scrollst und die Beantwortung liest. Die Lösung ist stets mit einem grünen Block markiert.  **Wichtige Empfehlung: Auch, wenn das nun doppelt (bzw. mehrfach) gesagt wird, probier dich bitte erst selbst an einer möglichen Lösung aus, bevor du dir die Auflösung ansiehst.**  **Wie alle praktischen Tätigkeiten kannst du Programmieren nur durch Übung lernen. Selbst, wenn du nicht auf die Lösung kommen solltest, allein das aktive Nachdenken über sie und das Eintippen von Wegen wird dich zu einem/r besseren ProgrammierIn machen ;-)** a) Werte ändern und Key-Value-Paare hinzufügen und ändern =, um Einträge eines Dictionarys zu ändernDie **Keys** eines Dictionarys sind immutable - das heißt, sie **können nicht verändert werden**. Möchtest du einen Key ändern, geht das nur, indem du einen neuen Key mit einem Wert hinzufügst und den unerwünschten löschst.  Die **Values** hingegen können wie gewohnt mit dem Zuweisungsoperator = upgedatet werden:<jupyter_code>student1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor', 'Semester': 1,\
            'Vollzeitstudium': True}

student1['Semester'] = 2

print(student1)<jupyter_output><empty_output><jupyter_text>Gibst du einen bereits vorhandenen Key an, wird dessen ursprünglicher Wert mit dem neuen überschrieben. Keys sind unique - es kann den gleichen Key nicht zwei Mal geben. Achte also stets darauf, bei Zuweisungen nur Keys zu überschreiben, die auch tatsächlich überschrieben werden sollen. Sonst kann es zu Datenverlust kommen!   Hinzufügen eines Key-Value-PairsWie im vorhergehenden Notebook erwähnt, sind die **Keys** eines Dictionarys immutable - sie **können nicht verändert werden**. Möchtest du einen Key ändern, geht das nur, indem du einen neuen Key mit einem Wert hinzufügst und den unerwünschten löschst.  An einem beispielhaften Dictionary zu den Einwohnern (engl.: population) pro km² in Berlins Bezirken siehst du nun die einfachste Variante, ein Key-Value-Paar hinzuzufügen:<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 5574, 'Neukölln': 7338}

berlin_pop['Tempelhof-Schönerg'] = 6624

print(berlin_pop)<jupyter_output><empty_output><jupyter_text>Um einen neuen Key hinzuzufügen, brauchst du keinen Index anzugeben, denn ein Dictionary ist per se ungeordnet.  Du fügst über die Index-Notation an dem Dictionary  dct['k']  und mit dem Zuweisungsoperator = dem neuen Key einen Value hinzu.   Änderung eines Keys  Um nun einen Key zu ändern, muss ein neuer Key hinzugefügt und der zu ändernde gelöscht werden.  Die Einwohnerzahl von 'Mitte' ist eigentlich die von 'Lichtenberg'. Wie du einen Eintrag anhand seines Indizes löschst, hast du im Kapitel "3.4 Lists" gelernt.  **Probier selbst, das Dictionary zu korrigieren, bevor du dir die Lösung weiter unten ansiehst.**<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 5574, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}<jupyter_output><empty_output><jupyter_text>Lösung:<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 5574, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}

berlin_pop['Lichtenberg'] = 5574

print(berlin_pop)
del berlin_pop['Mitte']
print(berlin_pop)<jupyter_output><empty_output><jupyter_text>Das Dictionary ist somit korrigiert! .update(), um Key-Value-Paare inzuzufügen und zu ändernMit ``.update()`` können nicht nur Key-Value-Paare hinzugefügt und geändert, es können auch zwei Dictionarys miteinander verschmolzen werden.  Beispiel für das Hinzufügen eines Key-Value-Paars:<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 9733, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}

berlin_lichtenberg = {'Lichtenberg': 5574}

berlin_pop.update(berlin_lichtenberg)

print(berlin_pop)<jupyter_output><empty_output><jupyter_text>Das zweite Dictionary (berlin_lichtenberg) wurde nahtlos in das erste (berlin_pop) eingefügt.  ``.update()`` ist auch praktisch, um ein leeres Dictionary zu befüllen:<jupyter_code>new_dct = {}

new_dct.update(berlin_pop)

print(new_dct)<jupyter_output><empty_output><jupyter_text>Die Key-Value-Paare von **berlin_pop** wurden in das leere Dictionary (**new_dict**) eingefügt.  Wird ein Wert in new_dict geändert, ändert sich der entsprechende Eintrag im Original-Dictionary nicht:<jupyter_code>new_dct['Mitte'] = 8000

print(new_dct)
print(berlin_pop)<jupyter_output><empty_output><jupyter_text>``.update()`` für Dictionarys funktioniert also ähnlich wie ``.copy()`` für Listen. Die Daten von flachen Dictionarys bleiben von ihrem Original unabhängig. Es ist außerdem äquivalent zu ``lst1 + lst2``, denn mit + wurden auch 2 Listen miteinander verschmolzen (engl.: merged).  Weil die Keys eines Dictionarys unique sind, gibt es nicht zwei gleiche Keys und deshalb werden gleichnamige Keys überschrieben, wenn sie upgedatet werden.  Wird also new_dct mit einem Dictionary upgedatet, das gleichnamige Keys enthält (berlin_pop), werden die zugehörigen Werte in new-dct überschrieben. Der Wert von 'Mitte' ändert sich durch ``.update()``. Der eben gesetzte Wert von 8000 wird mit dem ursprünglichen Wert aus **berlin_pop** überschrieben:<jupyter_code>new_dct.update(berlin_pop)

print(new_dct)
print(berlin_pop)<jupyter_output><empty_output><jupyter_text>Deshalb ist Vorsicht geboten, wenn du ``.update()`` verwendest. Achte darauf, keine Keys zu überschreiben, die nicht überschrieben werden sollen.  Du kannst mit ``.update()`` auch gleichzeitig ein weiteres Dictionary **und** ein Key-Value-Paar in ein Dictionary einfügen:<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 9733, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}

berlin_lichtenberg = {'Lichtenberg': 5574}

berlin_pop.update(berlin_lichtenberg, Reinickendorf = 2970)

print(berlin_pop)<jupyter_output><empty_output><jupyter_text>**=, um Werte in nested Dictionarys zu ändern**Du hast nun das Handwerkszeug, um den Namen '<NAME>' in '<NAME>' zu ändern.  **Weiter unten steht die Lösung. Probier deine eigene Lösung in der nächsten Code-Zelle aus:**<jupyter_code>students = dict(stud1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor'},
                stud2 = {'Name': '<NAME>', 'Alter': 21, 'Studiengang': 'Wirtschaftsinformatik Master'},
                stud3 = {'Name': '<NAME>', 'Alter': 24, 'Studiengang': 'Volkswirtschaftslehre Bachelor'})<jupyter_output><empty_output><jupyter_text>Lösung:<jupyter_code>students = dict(stud1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor'},
                stud2 = {'Name': '<NAME>', 'Alter': 21, 'Studiengang': 'Wirtschaftsinformatik Master'},
                stud3 = {'Name': '<NAME>', 'Alter': 24, 'Studiengang': 'Volkswirtschaftslehre Bachelor'})

students['stud3']['Name'] = '<NAME>'

students<jupyter_output><empty_output><jupyter_text>Auch ein weiteres **Subdictionary** kannst du problemlos mit der gleichen Notation **einfügen**:<jupyter_code>students = dict(stud1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor'},
                stud2 = {'Name': 'Alpha Xylophon', 'Alter': 21, 'Studiengang': 'Wirtschaftsinformatik Master'},
                stud3 = {'Name': '<NAME>', 'Alter': 24, 'Studiengang': 'Volkswirtschaftslehre Bachelor'})


students['stud4'] = {'Name': '<NAME>', 'Alter': 27, 'Studiengang': 'Biologie'}

students<jupyter_output><empty_output><jupyter_text>Dafür gibst du nach dem Dictionary in eckigen Klammern den neuen Key an und nach dem Zuweisungsoperator = das Dictionary, das als Subdictionary unter diesem Key eingefügt werden soll.  **.update(), um Werte in nested Dictionarys zu ändern**Innerhalb der Funktionsklammern von ``.update()`` kannst du ein weiteres Dictionary und dessen Key direkt übergeben:<jupyter_code>students = dict(stud1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor'},
                stud2 = {'Name': 'Alpha Xylophon', 'Alter': 21, 'Studiengang': 'Wirtschaftsinformatik Master'},
                stud3 = {'Name': '<NAME>', 'Alter': 24, 'Studiengang': 'Volkswirtschaftslehre Bachelor'})

students.update(stud4 = {'Name': '<NAME>', 'Alter': 27, 'Studiengang': 'Biologie'})

students<jupyter_output><empty_output><jupyter_text>Achte dabei darauf, den Key nicht als Integer oder String zu übergeben, da Python solche Variablennamen vor dem Zuweisungsoperator **=** nicht interpretieren kann (dieses Verhalten wie das weiter oben besprochene bei der Festlegung von Keys in ``dict()``).  Es reicht eine Key-Angabe wie im Beispiel oben mit stud4, ohne Anführungsstriche und beginnend mit einem Buchstaben.  Du kannst, wie bereits anhand eines flachen Dictionarys demonstriert, auch die Variable eines Dictionarys an ``.update()`` übergeben:<jupyter_code>students = dict(stud1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor'},
                stud2 = {'Name': 'Alpha Xylophon', 'Alter': 21, 'Studiengang': 'Wirtschaftsinformatik Master'},
                stud3 = {'Name': '<NAME>', 'Alter': 24, 'Studiengang': 'Volkswirtschaftslehre Bachelor'})

new_student = {'stud4': {'Name': '<NAME>', 'Alter': 27, 'Studiengang': 'Biologie'}}

students.update(new_student)

students<jupyter_output><empty_output><jupyter_text>Auch für die folgende Fragestellung hast du bereits das Handwerkszeug, um sie zu lösen. Für alle Fälle steht die Lösung weiter unten.  **Wie kannst du den Key eines Subdictionarys ändern?****Ändere exemplarisch mit "=" bei "stud4" den Key 'Alter' in 'age' und anschließend mit ".update()" den Key 'Studiengang' in 'subject.**<jupyter_code>students = dict(stud1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor'},
                stud2 = {'Name': 'Alpha Xylophon', 'Alter': 21, 'Studiengang': 'Wirtschaftsinformatik Master'},
                stud3 = {'Name': '<NAME>', 'Alter': 24, 'Studiengang': 'Volkswirtschaftslehre Bachelor'},
                stud4 = {'Name': '<NAME>', 'Alter': 27, 'Studiengang': 'Biologie'})<jupyter_output><empty_output><jupyter_text>Lösung:<jupyter_code>students = dict(stud1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor'},
                stud2 = {'Name': 'Alpha Xylophon', 'Alter': 21, 'Studiengang': 'Wirtschaftsinformatik Master'},
                stud3 = {'Name': '<NAME>', 'Alter': 24, 'Studiengang': 'Volkswirtschaftslehre Bachelor'},
                stud4 = {'Name': '<NAME>', 'Alter': 27, 'Studiengang': 'Biologie'})

students['stud4'] = {'Name': '<NAME>', 'age': 27, 'Studiengang': 'Biologie'}

students<jupyter_output><empty_output><jupyter_text>Zur Änderung eines Subkeys kannst du dem zugehörigen Superkey ein Dictionary mit dem geänderten Key zuweisen.  Diese Fragestellung ist auch über ``.update()`` lösbar.<jupyter_code>students = dict(stud1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor'},
                stud2 = {'Name': 'Alpha Xylophon', 'Alter': 21, 'Studiengang': 'Wirtschaftsinformatik Master'},
                stud3 = {'Name': '<NAME>', 'Alter': 24, 'Studiengang': 'Volkswirtschaftslehre Bachelor'},
                stud4 = {'Name': '<NAME>', 'Alter': 27, 'Studiengang': 'Biologie'})

students['stud4'].update({'Name': '<NAME>', 'age': 27, 'subject': 'Biologie'})

students<jupyter_output><empty_output><jupyter_text>Oder in anderer Schreibweise über ``.update()`` (am Beispiel von **'name'**):<jupyter_code>students = dict(stud1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor'},
                stud2 = {'Name': 'Alpha Xylophon', 'Alter': 21, 'Studiengang': 'Wirtschaftsinformatik Master'},
                stud3 = {'Name': '<NAME>', 'Alter': 24, 'Studiengang': 'Volkswirtschaftslehre Bachelor'},
                stud4 = {'Name': '<NAME>', 'Alter': 27, 'Studiengang': 'Biologie'})

students.update(stud4 = {'name': '<NAME>', 'age': 27, 'subject': 'Biologie'})

students<jupyter_output><empty_output><jupyter_text>**Achtung: Erstellst du ein Dictionary mit Startwerten über ``.fromkeys()`` und willst du dessen Keys später über ``.update()`` befüllen, zeigt Python dieses merkwürdige Verhalten:**<jupyter_code>stud_lst = ['s1', 's2', 's3']

students = dict.fromkeys(stud_lst, {})

students
students['s1'].update({'Name': '<NAME>'})

students<jupyter_output><empty_output><jupyter_text>Obwohl nur der Key **'s1'** angegeben wurde, wurden die Werte an jeden Key übertragen.  **Übergibst du in den Funktionsklammern von ``.update()`` den Key inklusive Subdictionary, funktioniert die Zuweisung korrekt:**<jupyter_code>stud_lst = ['s1', 's2', 's3']

students = dict.fromkeys(stud_lst, {})

students.update(s1 = {'Name': '<NAME>'} )

students<jupyter_output><empty_output><jupyter_text>**Wertänderungen über den Zuweisungsoperator ``=`` funktionieren hingegen wie gewohnt bei einem über ``dict.fromkeys()`` erstellten Dictionary:**<jupyter_code>stud_lst = ['s1', 's2', 's3']

students = dict.fromkeys(stud_lst, {})

students['s1'] = {'Name': '<NAME>'}

students<jupyter_output><empty_output><jupyter_text>**Wird das Dictionary nicht mit ``.fromkeys()`` erstellt, funktioniert die Wertänderung über ``.update()`` korrekt:**<jupyter_code>students = {'s1': {}, 's2': {}, 's3': {}}

students['s1'].update({'Name': '<NAME>'})

students<jupyter_output><empty_output><jupyter_text>Tipp: Verwende dict.fromkeys() deshalb niemals im Zusammenhang mit dieser Syntax von .update(): dct['Key1'].update({'Subkey1': 'Subvalue1'})   3.5.4 b) Dictionary-Einträge/-Werte entfernen .pop(), um Dictionary-Einträge zu entfernenDie Funktion ``.pop()`` kennst du schon von Listen. Dort hat ``.pop()`` ohne ein übergebenes Argument automatisch den letzten Listeneintrag entfernt und diesen zur Kontrolle noch einmal ausgegeben. Erinnerung:<jupyter_code>lst = [1, 2, 3]

lst.pop()
print(lst)<jupyter_output><empty_output><jupyter_text>Bei Dictionarys funktioniert ``.pop()`` etwas anders: ``.pop()`` benötigt immer einen Key als Argument und löscht somit nicht automatisch den letzten Eintrag.Wie bei Lists gibt ``.pop()`` den Wert des Keys aus, der gelöscht wurde (nicht den Key).   Beispiel:<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 9733, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}

berlin_pop.pop('Neukölln')
berlin_pop<jupyter_output><empty_output><jupyter_text>``dct.pop('k')`` ist damit äquivalent zu ``del dct['k']``, nur, dass der gelöschte Wert über ``del`` nicht noch einmal ausgegeben wird.  Soll ein Key gelöscht werden, der in der Liste nicht existiert, führt das zu einem KeyError:<jupyter_code>berlin_pop.pop('Spandau')<jupyter_output><empty_output><jupyter_text>.popitem(), um den zuletzt hinzugefügten Dictionary-Eintrag mit zu entfernenFast wie ``lst.pop()`` funktioniert hingegen ``dct.popitem()``: Bei einer Liste entfernt ``lst.pop()`` den **letzten Eintrag**, bei Dictionarys entfernt ``dct.popitem()`` den **zuletzt hinzugefügten Eintrag**. Den letzten Eintrag kann es nicht entfernen, da Dictionarys nicht geordnet sind. Es würde einen zufällig ausgewählten Eintrag löschen.  Stattdessen speichert Python, welcher Eintrag dem Dictionary zuletzt hinzugefügt wurde und löscht diesen. Beispiel:<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 9733, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}

berlin_pop['Charlottenburg-Wilmersdorf'] = 5289

print(berlin_pop)
berlin_pop.popitem()
print(berlin_pop)<jupyter_output><empty_output><jupyter_text>Im Gegensatz zu ``dct.pop('k')`` gibt ``dct.popitem()`` nicht nur den gelöschten Wert des Keys aus, sondern das gesamte Key-Value-Paar.  In dieser Funktion steht "item"  für ein Key-Value-Paar bzw. ein Element des Dictionarys.   .clear() zum Leeren eines DictionarysWie bei Listen, leert ``.clear()`` die gesamte Datenstruktur Dictionary. Beispiel:<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 9733, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}

berlin_pop.clear()

print(berlin_pop)<jupyter_output><empty_output><jupyter_text>del zum Löschen von Key-Value-Paaren und DictionarysEinen **Key und ein Subdictionary löschen** kannst du mit ``del``. Bei der Löschung über ``del`` wird der gelöschte Eintrag/Wert nicht noch einmal ausgegeben. Beispiel:<jupyter_code>students = dict(stud1 = {'Name': '<NAME>', 'Alter': 23, 'Studiengang': 'Wirtschaftsinformatik Bachelor'},
                stud2 = {'Name': '<NAME>', 'Alter': 21, 'Studiengang': 'Wirtschaftsinformatik Master'},
                stud3 = {'Name': '<NAME>', 'Alter': 24, 'Studiengang': 'Volkswirtschaftslehre Bachelor'})

students
del students['stud2']
students<jupyter_output><empty_output><jupyter_text>b) .copy() zum Kopieren von DictionarysWie bei Listen, wird auch bei Dictionarys über ``.copy()`` eine flache Kopie erstellt.  Erinnerung: Änderungen an einer flachen Kopie bewirken Änderungen am Original.  Bei einem flachen Dictionary (das auch flach bleiben sollte), erhältst du mit ``.copy()`` trotzdem eine vom Original unabhängige Kopie. Beispiel:<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 9733, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}

berlin_pop2 = berlin_pop.copy()

print(berlin_pop)
print(berlin_pop2)<jupyter_output><empty_output><jupyter_text>**Füge nun den Eintrag "Reinickendorf: 2970" in der Kopie hinzu und überprüfe, ob sich auch das Original verändert.**<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 9733, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}

berlin_pop2 = berlin_pop.copy()<jupyter_output><empty_output><jupyter_text>Lösung:<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 9733, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}

berlin_pop2 = berlin_pop.copy()

berlin_pop2['Reinickendorf'] = 2970

print(berlin_pop)
print(berlin_pop2)<jupyter_output><empty_output><jupyter_text>Das Original blieb unverändert! Du erhältst über ``.copy()`` also eine tiefe Kopie eines flachen Dictionarys (analog zu List).  **Wie sieht das wohl bei einem tiefen Dictionary aus?**Übung zum Kopieren und Bearbeiten eines tiefen Dictionarys:     **a)** Füge dem Bezirk **Friedrichshain-Kreuzberg**, statt der Einwohnerzahl pro qm², ein **Subdictionary** ein, welches die **Einwohnerzahl pro qm²** enthält und die **Gesamteinwohnerzahl (289762)**.  **b)** Erstelle anschließend über ``.copy()`` eine **Kopie** dieses Dictionarys.**c)** **Lösche** anschließend in der Kopie den Eintrag zur **Gesamteinwohneranzahl in Friedrichshain-Kreuzberg**.  **d)** Vergleiche die **ID des Subdictionarys** der Kopie mit der ID des Subdictionarys des Originals.**e)** Überprüfe, ob sich die **Originalliste verändert** hat. Was schlussfolgerst du aus **d)** und **e)**?Es gibt mehrere Wege, diese Aufgabe zu lösen. Auch hier zählt wieder das funktionierende Ergebnis, das nicht der Aufgabenstellung widerspricht.<jupyter_code># a)

berlin_pop = {'Friedrichshain-Kreuzberg': 14373, 'Mitte': 9733, 'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}


# b)


# c)


# d)


# e)<jupyter_output><empty_output><jupyter_text>Du solltest zu dem Ergebnis gekommen sein, dass die IDs der Subdictionarys identisch sind und das Original-Dictionary bzw. dessen Subdictionary verändert wurde.  Die Schlussfolgerung lautet:  **``.copy()`` erstellt flache Kopien von tiefen/nested Dictionarys (analog zu tiefen Listen).**Solltest du Schwierigkeiten mit der letzten Übung gehabt haben, sieh dir bitte noch einmal das Kapitel "3.4.4 Spezielle List-Funktionen" und darin die Punkte g) und h) an.  Die dort beschriebenen Beispiele gelten analog zu Dictionarys.  **Wie kannst du eine tiefe Kopie eines tiefen Dictionarys erstellen?****Probier es erst selbst aus, indem du eine tiefe Kopie von "berlin_pop" erstellst, einen Eintrag in dessen Subdictionary veränderst und die Kopie anschließend mit dem Original vergleichst.**<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': {'Einw./qm²': 14373, 'Gesamteinw.': 289762}, 'Mitte': 9733,\
              'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}<jupyter_output><empty_output><jupyter_text>Lösung:<jupyter_code>import copy

berlin_pop = {'Friedrichshain-Kreuzberg': {'Einw./qm²': 14373, 'Gesamteinw.': 289762}, 'Mitte': 9733,\
              'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}

berlin_pop2 = copy.deepcopy(berlin_pop)

print(berlin_pop)
print(berlin_pop2)
berlin_pop2['Friedrichshain-Kreuzberg']['Einw./qm²'] = 111111

print(berlin_pop)
print(berlin_pop2)<jupyter_output><empty_output><jupyter_text>Das Original-Dictionary wurde nicht verändert :-)Schlussfolgerungen zu tiefen und flachen Kopien von Dictionarys (analog zu Listen):    * ist und bleibt dein Dictionary ein **flaches Dictionary**, kannst du mit ``.copy()`` eine tiefe Kopie von ihm erzeugen* für ein **tiefes Dictionary** (= verschachteltes/nested Dictionary) verwende für eine tiefe Kopie über ``import copy`` die Funktion ``dct.copy.deepcopy()`` c) len(), um die Länge eines Dictionarys festzustellenDiese Funktion kennst du, denn ``len()`` wird auch verwendet, um die die Zeichenanzahl in einem String und die Gesamtanzahl der Einträge in einer Liste zu messen. Beispiel:<jupyter_code>engl_dict = {'Handel': 'trade', 'Steuern': 'taxes', 'Verhandlung': 'negotiation'}

len(engl_dict)<jupyter_output><empty_output><jupyter_text>``len()`` zählt die Key-Value-Paare eines Dictionarys.**Lass dir nun die Anzahl der Einträge des Subdictionarys von "Friedrichshain-Kreuzberg" ausgeben.**<jupyter_code>berlin_pop = {'Friedrichshain-Kreuzberg': {'Einw./qm²': 14373, 'Gesamteinw.': 289762}, 'Mitte': 9733,\
              'Neukölln': 7338, 'Tempelhof-Schönerg': 6624}<jupyter_output><empty_output><jupyter_text>Lösung:<jupyter_code>len(berlin_pop['Friedrichshain-Kreuzberg'])<jupyter_output><empty_output><jupyter_text>d) str(), um ein Dictionary in einen String umzuwandeln  Wenn du ein Dictionary textuell weiterverarbeiten möchtest, kannst du es mit ``str()`` leicht in einen String umwandeln. Beispiel:<jupyter_code>engl_dict = {'Handel': 'trade', 'Steuern': 'taxes', 'Verhandlung': 'negotiation'}

str(engl_dict)<jupyter_output><empty_output><jupyter_text>Mit dem Dictionary als String kannst du über String-Funktionen und Slicing einzelne Wörter verändern und sie extrahieren, z.B. als Listeneinträge (siehe Kapitel "3.2.9 g) split()").  Das funktioniert auch mit einem Dictionary mit numerischen Werten, denn ``str()`` wandelt den **gesamten** Dictionary-Inhalt in **einen** String um.  Abschließende Übung zu dieser Einheit: Lies dir erst die komplette Aufgabe durch, damit du sie richtig lösen kannst.      Du bearbeitest ein Preis-Dictionary des Obst- und Gemüsehändlers "<NAME>". Das Preis-Dictionary beinhaltet Fruchtgemüse. Das sind Sorten, die eine Mischung aus Frucht und Gemüse sind.      **a)** Für eine weitere Preisliste, die diverse Tomatensorten enthalten soll, brauchst du eine Kopie des aktuellen Dictionarys. Erstelle diese.**b)** Füge der Kopie das gegebene "**tomatoes**"-Dictionary an dem Key **'Tomate'** hinzu und **gleichzeitig** den Preis für **Paprika**, der 1,19 Euro beträgt.**c)** Entferne den Eintrag **'Tomate'** aus **fruitveg_prices** (dem Original) so, dass du gleichzeitig sichergehen kannst, dass der richtige Wert gelöscht wurde.  **d)** **'Paprika'** wird doch **nicht** geliefert. Entferne den Eintrag aus dem kopierten Dictionary so, dass dir das gelöschte Key-Value-Paar angezeigt wird. Tipp: Das funktioniert nur, weil **'Paprika'** zuletzt hinzugefügt wurde.Stelle auf eine dir passende Weise während der Bearbeitung dieser Aufgabe sicher, dass beide Dictionarys unabhängig voneinander sind.<jupyter_code># a)

fruitveg_prices = dict(Tomate = 0.9, Aubergine = 1.0, Gurke = 0.95)
# b)

tomatoes = dict(Cherrytomaten = 1.99, Rispentomaten = 2.05, Minipflaumentomaten = 1.49)
# c)


# d)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12469916377727921, 'fraction_numerical': 0.02133387721802978, 'mean_word_length': 6.1060869565217395, 'pattern_counts': {'":': 0, '<': 199, '<?xml version=': 0, '>': 199, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '39', 'dir': 'jupyter-structured-clean-dedup', 'id': '450316', 'license': 'MIT', 'n_tokens_mistral': 9013, 'n_tokens_neox': 8821, 'n_words': 2433, 'path': '3 Python Grundlagen/3.5 Dictionaries/3.5.4 Die wichtigsten Dictionary-Funktionen.ipynb', 'repo_name': 'hannesrothe/dataliteracy', 'size': '24732'}