# ein Dictionary invertieren: Werte werden zu Schlüsseln und Schlüssel zu
# Werten

# Original-Dictionary
d = {
   1: 'eins',
   2: 'zwei',
   3: 'drei',
  '3': 'drei',
}

# Dictionary ausgeben
print(d)

# Variante 1: das invertierte Dictionary über eine Dictionary Comprehension
# generieren; man verliert aber Werte, wenn wie oben ein Wert des
# Original-Dictionarys mehreren Schlüsseln zugeordnet ist:
print({d[key] : key for key in d})
#   {'eins': 1, 'zwei': 2, 'drei': '3'}  ==> die Integer-Zahl 3 geht hier verloren
#
# korrekt wäre:
#
#   {'eins': [1], 'zwei': [2], 'drei': [3, '3']}

# Variante 2 erzeugt dieses korrekte Dictionary

# ein leeres invertiertes Dictionary anlegen
inv_d = {}

# wir durchlaufen alle Schlüssel-Wert-Paare des Original-Dictionarys; da
# mehreren Schlüsseln des Original-Dictionarys derselbe Wert zugeordnet sein
# kann, verwalten wir im invertierten Dictionary pro Key eine Liste von Werten,
# um keine Daten zu verlieren
for key, val in d.items():
    if val not in inv_d:
        # der aktuelle Wert des Original-Dictionarys existiert noch nicht als
        # Key des invertierten Dictionarys, daher legen wir ihn an und weisen
        # ihm die leere Liste als Wert zu
        inv_d[val] = []
    # den aktuellen Schlüssel des Original-Dictionarys als Wert an die
    # Werte-Liste anhängen
    inv_d[val].append(key)

print(inv_d)

# alternativ zur eigenen Implementierung oben kann man ein defaultdict aus dem
# Modul collections nutzen
from collections import defaultdict

# als Default-Element nutzen wir die Klasse list, also eine leere Liste; diese
# wir einem noch nicht existierenden Schlüssel automatisch beim ersten Zugriff
# als Wert zugewiesen
inv_dd = defaultdict(list)

# der obige Test auf die Existenz des Schlüssels und die explizite Zuweisung
# der leeren Liste entfällt hier
for key, val in d.items():
    inv_dd[val].append(key)

# Ausgabe des defaultdict-Objekts
print(inv_dd)

# Ausgabe des daraus erstellten normalen Dictionarys
print(dict(inv_dd))
