Dictionary umdrehen

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
ElastischerHosenbund
User
Beiträge: 12
Registriert: Donnerstag 22. Juli 2021, 22:52

Hallo ich bin noch relativ neu in Python (und programmierung im allgemeinen) und komme mit folgender Aufgabe nicht so richtig klar:
Ich soll folgendes Dictionary umdrehen:

Code: Alles auswählen

alter = {
    'lisa': 19,
    'michael': 22,
    'sebastian': 18,
    'zheng': 23,
    'theo': 26,
    'alex': 19,
    'nick': 19
}
Ergebnis: {19: ['lisa', 'alexandra', 'nick'], 22: ['michael'], 23: ['zheng'], 26: ['theo']}

Ich hab auch eine "Lösung"... Ihr werdet vermutlich die Hände überm Kopf zusammenschlagen:

Code: Alles auswählen

def dreheDic(d):
    x = d.items()
    values = list(d.values())
    names = []
    for i in d:
        l = []
        for j, k in x:
            if k == d[i] and k not in names:
                l.append(j)
        names.append(l)

    bereinigt = []
    for i in names:
        if i not in bereinigt:
            bereinigt.append(i)

    x = zip(bereinigt, values)
    alter = []
    namen = []
    for i, j in x:
        namen.append(i)
        alter.append(j)
    return(list(zip(namen,alter)))


print(dreheDic(alter))
Meine Idee war:
Sich erst die Schlüssel zu besorgen, die auf den gleichen Value zeigen. Diese habe ich dann in "names" als Liste gespeichert.
Da meine 1. For-Schleife jedoch nicht sehr effizienz arbeitet muss danach die Liste "names" von doppelten Einträgen "bereinigt" werden.
Das ergebnis speichere ich dann in "bereinigt". Anschließend zippe ich das ganze zusammen und... Ach... Das ist einfach ein riesen Kuddelmuddel bei dem ich schon selber nicht mehr durchschaue..

Meine Ausgabe schaut nun jedenfalls so aus:

Code: Alles auswählen

[(['lisa', 'alex', 'nick'], 19), (['michael'], 22), (['sebastian'], 18), (['zheng'], 23), (['theo'], 26)]
Ein grausames "Etwas" Aus Listen & Tupeln, welches ich nun nicht in in ein Dictionary umgewandelt bekomme...
... Und, wenn ich mir das ganze so anschaue eigentlich auch gar nicht mehr möchte.. Die Lösung ist einfach grausam anzusehen.. Das seh selbst ich als Anfänger... :-D

Wie würdet ihr das ganze angehen?
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Ich würde es mit einem defaultdict machen:
https://docs.python.org/3/library/colle ... ct-objects

Code: Alles auswählen

from collections import defaultdict

neuer = defaultdict(list)

alter = {
    'lisa': 19,
    'michael': 22,
    'sebastian': 18,
    'zheng': 23,
    'theo': 26,
    'alex': 19,
    'nick': 19
}

for name, age in alter.items():
    neuer[age].append(name)

# Umwandlung in dict() ist optional, man kann es auch als defaultdict belassen.
print(dict(neuer))

"""
Ausgabe:
{19: ['lisa', 'alex', 'nick'], 22: ['michael'], 18: ['sebastian'], 23: ['zheng'], 26: ['theo']}
"""
Zuletzt geändert von rogerb am Freitag 23. Juli 2021, 08:00, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Funktionen schreibt man wie Variablennamen komplett klein. Benutze keine Abkürzungen oder einbuchstabige Variablennamen, wenn sie das Verstehen des Codes so schwer machen, wie bei Dir. `x` für items? `d` für `input_dictionary` `i` für was eigentlich?
`l` sollte man gar nicht verwenden, weil es leicht mit 1 verwechselt werden kann.
Wie jetzt vernünftige Namen vergeben will, komme ich zu dem Problem, dass ich `k` gerne in `alter` umbennenen wollte, weil die Werte des Wörterbuchs das Alter enthalten. Damit `k in names` zu `alter in names`, woran man gleich sehen kann, dass da ein Fehler ist.

Überarbeite also als erstes Deinen Code nochmal, und gib allen Variablen aussagekräftige Namen und korrigiere die falschen Namen.
Dann können wir weiter am Algorithmus arbeiten.
ElastischerHosenbund
User
Beiträge: 12
Registriert: Donnerstag 22. Juli 2021, 22:52

@roger b: Also so einfach kann das gehen.. Ugh. :( Vielen Dank!

@Sirius3: Ich habe mich eben nochmal rangesetzt und es überarbeitet.

Code: Alles auswählen

alter = {
    'lisa': 19,
    'michael': 22,
    'sebastian': 18,
    'zheng': 23,
    'theo': 26,
    'alex': 19,
    'nick': 19
}

def drehedic(dic):
    entries = dic.items()
    values = list(dic.values())
    group_names = []
    for entry in dic:
        names = []
        for name, age in entries:
            if age == dic[entry] and age not in names: ##"age not in names" ist überflüssig eig. glaube ich
                names.append(name)
        group_names.append(names)

    group_names_unique = []
    for entry in group_names:
        if entry not in group_names_unique:
            group_names_unique.append(entry)

    """
    1. Problem: Die erste for-Schleife arbeitet nicht richtig: Es müssen in der 2. For-Schleife
    Doppelte Listeneinträge entfernt werden --> group_names_unique

    """

    new_dict = zip(group_names_unique, values)
    ages = []
    names = []
    for age, name in new_dict:
        names.append(name)
        ages.append(age)

    return(dict(zip(names,ages)))
Seltsamerweise hat nun das Umwandeln in ein Dictionary im letzten Step einwandfrei funktioniert.. (Nun steht auch "dict" davor und nicht "list" hatte ich aber gestern auch schon versucht).
Die Ausgabe ist nun eigentlich genau so, wie ich sie haben möchte:
{19: ['lisa', 'alex', 'nick'], 22: ['michael'], 18: ['sebastian'], 23: ['zheng'], 26: ['theo']}

Hm. Nur so ganz zufrieden bin ich dennoch noch nicht... Vor allem die erste For-Schleifen-Konstruktion schaut halt immernoch ziemlich besch**** aus und der letzte Teil sieht auch noch verbesserungswürdig aus... Oo
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@ElastischerHosenbund,

gibt es einen besonderen Grund, dass du das so umständlich machen willst?

1) Mit einem set() aus den Werten des alten Dictionaries bekommt man die Schlüssel des neuen Dictionaries. Das Ablegen in einem Set nimmt einem die Arbeit ab, weil automatisch doppelte Schlüssel entfernt werden.
2) Für jeden Schlüssel eine Liste vorbereiten. Das kann man in einer dictionary - comprehension erledigen.
3) Der Reihe nach einsortieren

So ginge es ohne defaultdict:

Code: Alles auswählen

alter = {
    "lisa": 19,
    "michael": 22,
    "sebastian": 18,
    "zheng": 23,
    "theo": 26,
    "alex": 19,
    "nick": 19,
}


def drehe_dictionary(alter):
    # neuen dictionary mit den Werten des alten als Schlüssel des neuen anlegen
    new_dictionary = {key: [] for key in set(alter.values())}

    # einsortieren des alten dictionaries in den neuen
    for key, value in alter.items():
        new_dictionary[value].append(key)
    return new_dictionary


print(drehe_dictionary(alter))
"""
Ausgabe:
{18: ['sebastian'], 19: ['lisa', 'alex', 'nick'], 22: ['michael'], 23: ['zheng'], 26: ['theo']}
"""
ElastischerHosenbund
User
Beiträge: 12
Registriert: Donnerstag 22. Juli 2021, 22:52

Einen triftigen Grund habe ich eigentlich nicht..Nur weil Siriuis3 schrieb ich solle meinen Code nochmal überarbeiten und ich mich dann doch nicht zufriedengeben wollte, hab ich das ganze nochmal angepackt. Es ist in der Zwischenzeit sogar noch monströser geworden, damit das ganze auch bei Values funktioniert, die keine Zahlen sind... :-D

Aber damit lasse ich es nun auch gut sein denke ich. Zumindest funktioniert meine Lösung nun auch und ich hab einiges nochmal bei gelernt. Jetzt schau ich mir deine beiden Lösungen nochmal genauer an :)
Antworten