Seite 1 von 1

Listen und Dictionarys umwandeln

Verfasst: Mittwoch 8. Februar 2023, 21:01
von PythonNeuling8
Hallo, ich würde gerne eure Meinung hören zu folgenden Programm, also ob man sie noch etwas kompakter formulieren kann, aber ohne importierte Module, beziehungsweise ob sie im Großen und Ganzen die jeweilige Aufgabenstellung gut erfüllen (Ich bin frischer Anfänger). Bei der Lösung musste ich mich auf elementare Programmiermethoden beschränken, also auf gewöhnliche Schleifen etc. :)

1a) Implementieren Sie eine Funktion listToDict(a, k), die eine Tabelle a, also eine Liste von Listen, und einen Index k als Argumente erwartet und die Tabelle in ein Dictionary umwandelt, wobei die k-te Spalte als Schlüssel interpretiert wird. Meine Lösung:

Code: Alles auswählen

def listToDict(a, k):
    # Erstellen von Dictionary und Liste, die die Elemente der k-ten Spalte enthält
    dc = {}                      
    l = []
            
    # Entfernen der k-ten Spalte der Tabelle und Hinzufügen dieser in eine separate Liste,
    # die damit die Schlüssel des Dictionarys enthält
    for i in range(len(a)):
        l.append(a[i][k])
        a[i].remove(a[i][k])
    # jedem Schlüssel, also i-tem Element der sep. Liste, die restliche i-te Liste aus a zuordnen
    for i in range(len(l)):
        dc[l[i]] = a[i]
        
    return dc

# Testprogramm
a = [["Mustermann", "Max", 1234],["Exemplaris", "Emilie", 7890]]
b = [["Mustermann", "Max", 1234, 'Berlin'],["Exemplaris", "Emilie", 7890, 'Kiel'],
     ["Richter", "Horst", 4444, 'München']]

d = listToDict(a, 2)
print(d)   # Ausgabe {1234: ['Mustermann', 'Max'], 7890: ['Exemplaris', 'Emilie']}

d2 = listToDict(b,1)
print(d2)    # Ausgabe {'Max': ['Mustermann', 1234, 'Berlin'], 'Emilie': ['Exemplaris', 7890, 'Kiel'], 'Horst': ['Richter', 4444, 'München']}
b) Implementieren Sie eine Funktion dictToList(d, k), die ein Dictionary d und einen Index k als Argumente erwartet und eine Tabelle (Liste von Listen) mit allen Einträgen des Dicitonaries liefert, wobei der Schlüssel in die k-te Spalte eingetragen werden soll. Man darf davon ausgehen, dass es sich bei den Einträgen in dem Dictionary um Listen handelt. Meine Lösung:

Code: Alles auswählen


def dictToList(d, k):
    # leere Liste, in die die Dictionary-Einträge eingetragen werden
    l = []
    # fügen jeden Dictionary-Wert zur Liste hinzu
    for wert in d.values():
        l.append(wert)
    # erstellen eine Liste mit allen Schlüsseln 
    key_list = []
    for wert in d.keys():
        key_list.append(wert)
    # fügen jeder Tabellenzeile an der k-ten Stelle den jeweiligen Schlüssel hinzu mit insert()
    for i in range(len(key_list)):
        l[i].insert(k,key_list[i])
        
    return l

# Testprogramm
d = {1234: ["Mustermann", "Max"], 7890: ["Exemplaris", "Emilie"]}
a = dictToList(d, 1)
print(a)      # Ausgabe [['Mustermann', 1234, 'Max'], ['Exemplaris', 7890, 'Emilie']]


Re: Listen und Dictionarys umwandeln

Verfasst: Mittwoch 8. Februar 2023, 23:04
von __blackjack__
PythonNeuling8: Wie im anderen Thema schon angemerkt: Die Funktion verändert das Argument `a` — das ist falsch.

Auch was ich dort über kryptisch abgekürzte Namen gesagt habe gilt auch hier.

Bist Du sicher, dass die Werte die als Schlüssel dienen, aus den Listen entfernt bzw. eingefügt werden sollen?

Da man solche Werte nicht verändert, weil das zu schwer zu findenden Problemen führt, insbesondere wenn man nicht weiss wo diese Werte noch so überall im Programm referenziert werden, schreibt man Funktionen üblicherweise so, dass sie neue, veränderte Datenstrukturen anlegen, statt vorhandene/übergebene zu verändern.

Dann braucht man auch diese ganzen ``for i in range(len(some_sequence)):``-Schleifen nicht, denn die sind in Python ein „anti pattern“, weil man ja direkt, ohne den Umweg über einen Laufindex, auf die Elemente von Sequenzen zugreifen kann. Immer wenn man dieses Schleifenmuster sieht, sollte man kurz innehalten und überlegen was man da gerade falsch macht. Das man so eine Schleife tatsächlich braucht ist nämlich eher selten.

Hier eine kompakte Variante mit „comprehension“-Syntax, die aber auch mit ``for``-Schleifen nur zwei oder drei Zeilen länger werden:

Code: Alles auswählen

#!/usr/bin/env python3
from pprint import pprint


def table_to_mapping(rows, key_index):
    return {
        row[key_index]: row[:key_index] + row[key_index + 1 :] for row in rows
    }


def mapping_to_table(key_to_row, key_index):
    return [
        [*row[:key_index], key, *row[key_index:]]
        for key, row in key_to_row.items()
    ]


def main():
    table = [
        ["Mustermann", "Max", 1234, "Berlin"],
        ["Exemplaris", "Emilie", 7890, "Kiel"],
        ["Richter", "Horst", 4444, "München"],
    ]
    for key_index in [1, 2]:
        pprint(table_to_mapping(table, key_index))

    pprint(
        mapping_to_table(
            {1234: ["Mustermann", "Max"], 7890: ["Exemplaris", "Emilie"]}, 1
        )
    )


if __name__ == "__main__":
    main()
Ausgabe:

Code: Alles auswählen

{'Emilie': ['Exemplaris', 7890, 'Kiel'],
 'Horst': ['Richter', 4444, 'München'],
 'Max': ['Mustermann', 1234, 'Berlin']}
{1234: ['Mustermann', 'Max', 'Berlin'],
 4444: ['Richter', 'Horst', 'München'],
 7890: ['Exemplaris', 'Emilie', 'Kiel']}
[['Mustermann', 1234, 'Max'], ['Exemplaris', 7890, 'Emilie']]

Re: Listen und Dictionarys umwandeln

Verfasst: Donnerstag 9. Februar 2023, 10:51
von DeaD_EyE
Mal ganz naiv ohne dict/list comprehensions:

Code: Alles auswählen

def dict_to_list(data, position):
    result = []
    for key, values in data.items():
        # erstellt eine Kopie von row
        # und das verhindert, dass die values von data modifiziert werden
        row = list(values)
        # den Wert beim entsprechenden Index einfügen
        row.insert(position, key)
        result.append(row)
    return result


def list_to_dict(data, position):
    result = {}
    for row in data:
        row = list(row)
        # den Wert aus dem entsprechenden Index der Liste holen
        key = row.pop(position)
        result[key] = row
    return result


d = {1234: ["Mustermann", "Max"], 7890: ["Exemplaris", "Emilie"]}
a = dict_to_list(d, 1)
print(a)  # Ausgabe [['Mustermann', 1234, 'Max'], ['Exemplaris', 7890, 'Emilie']]
b = list_to_dict(a, 1)
print(b)
Bei dem Beispiel von __blackjack__ wird auch kopiert, da das Slicing auf eine Liste angewandt wird und das erstellt dann eine neue Liste.
Würde man einfach die Liste so nehmen wie sie ist und modifizieren (pop, insert, usw.), würde man die Daten modifizieren, die der Funktion übergeben worden sind.
Solche Effekte möchte man vermeiden, nutzt sie aber auch aus, wenn es sinnvoll ist, dass eine Funktion das übergebene Objekt verändert.

Ein Beispiel aus der Standardbibliothek ist z.B. random.shuffle. Die übergebene Liste wird gemischt und random.shuffle gibt es None zurück.


Um Listen zu kopieren:

Code: Alles auswählen

my_seq = [1,2,3]

my_copy1 = my_seq1[:] # <- Linting-Tools neigen dazu das aufgrund der besseren Lesbarkeit zu ersetzen
my_copy2 = my_seq.copy() # <- wird auch oft benutzt
my_copy3 = list(my_seq) # <- kommt öfters vor
my_copy4 = [*my_seq] # <- noch nirgendwo in freier Wildbahn gesehen
my_copy5 = my_seq + [] # erstellt auch eine Liste, indem my_seq mit einer leeren Liste erweitert wird. Aber auch das wird man kaum sehen.

Re: Listen und Dictionarys umwandeln

Verfasst: Donnerstag 9. Februar 2023, 10:55
von __blackjack__
Ist Code-Golf „freie Wildbahn“? Dort sieht man das Vorletzte öfter mal als Ersatz für den `list()`-Aufruf. 😎

Re: Listen und Dictionarys umwandeln

Verfasst: Donnerstag 9. Februar 2023, 11:13
von __deets__

Code: Alles auswählen

{**w1, **w2}
gestern zum ersten mal selbst benutzt. Finde ich praktisch zum layern von Woerterbuechern. Und geht natuerlich auch mit Listen.

Re: Listen und Dictionarys umwandeln

Verfasst: Freitag 10. Februar 2023, 15:43
von DeaD_EyE
__blackjack__ hat geschrieben: Donnerstag 9. Februar 2023, 10:55 Ist Code-Golf „freie Wildbahn“? Dort sieht man das Vorletzte öfter mal als Ersatz für den `list()`-Aufruf. 😎

Code: Alles auswählen

sieht_doof_aus_mit_nur_einem_element = [*entpacke_mich_und_pack_mich_wieder_ein]
Das ist noch Sinvoll.

Code: Alles auswählen

{**w1, **w2}
Mit nur einem Element würde ich das machen, wenn ich in einem großen Team wäre und genau wüsste, dass sich ein Entwickler garantiert darüber tierisch aufregen würde.

Re: Listen und Dictionarys umwandeln

Verfasst: Freitag 10. Februar 2023, 16:03
von __blackjack__
@DeaD_EyE: Bei Code-Golf geht es nicht ums aussehen oder guten Code sondern um kurzen Code, und ``list(a)`` ist deutlich länger als ``[*a]``. Eine Nische in Produktivcode wäre noch (Mikro)Optimierung — der Funktionsaufruf ist langsamer als der Bytecode der die literale Liste erzeugt.

Re: Listen und Dictionarys umwandeln

Verfasst: Freitag 10. Februar 2023, 17:14
von __deets__
DeaD_EyE hat geschrieben: Freitag 10. Februar 2023, 15:43

Code: Alles auswählen

{**w1, **w2}
Mit nur einem Element würde ich das machen, wenn ich in einem großen Team wäre und genau wüsste, dass sich ein Entwickler garantiert darüber tierisch aufregen würde.
Was denn fuer ein Element? Das sind zwei Woerterbuecher, die aufgrund von fehlendem Kontext natuerlich einfach generisch benannt sind. Die koennen beliebig viele Elemente haben, und das ganze steht fuer

Code: Alles auswählen

w3 = {}
w3.update(w1)
w3.update(w2)
Was natuerlich sehr praktisch ist, wenn man zB eine default-Konfiguration mit einer angegebenen Konfiguration ergaenzen will.

Re: Listen und Dictionarys umwandeln

Verfasst: Samstag 11. Februar 2023, 09:00
von snafu
__blackjack__ hat geschrieben: Freitag 10. Februar 2023, 16:03 @DeaD_EyE: Bei Code-Golf geht es nicht ums aussehen oder guten Code sondern um kurzen Code, und ``list(a)`` ist deutlich länger als ``[*a]``. Eine Nische in Produktivcode wäre noch (Mikro)Optimierung — der Funktionsaufruf ist langsamer als der Bytecode der die literale Liste erzeugt.
Wobei die Python-Entwickler in den letzten Monaten viel Energie in die Performance (u. a. mittels Spezialisierungen) gesteckt haben. Wenn man grundsätzlich weiß, dass äquivalenter Bytecode zum list()-Aufruf mit einem Argument möglich ist, dann wäre es ja nur logisch, diesen auch vor dem Kompilieren entsprechend umzuwandeln. Ob das inzwischen so gemacht wird, ggf. auch nur in Funktionen, die zum Optimieren "markiert" wurden, weiß ich aber aus dem Stegreif nicht. Was sich definitiv verbessert hat, ist die Laufzeit für den Aufruf für Builtin-Funktionen. Somit ist der Unterschied in aktuellen Python-Versionen eh nicht mehr so groß wie noch vor ein paar Jahren.

Re: Listen und Dictionarys umwandeln

Verfasst: Samstag 11. Februar 2023, 13:47
von __blackjack__
@snafu: Dazu müsste der Compiler ja wissen, dass bei ``list(a)`` der Name `list` tatsächlich für die eingebaute `list()`-Funktion steht. Würde mich wundern wenn die mittlerweile überhaupt *versuchen* so etwas zu erkennen. 100%ig ist das ja sowieso nicht machbar jede Mögliche kreative Art `list` neu zu definieren statisch zu erkennen.

Re: Listen und Dictionarys umwandeln

Verfasst: Montag 13. Februar 2023, 14:43
von DeaD_EyE
__deets__ hat geschrieben: Freitag 10. Februar 2023, 17:14
DeaD_EyE hat geschrieben: Freitag 10. Februar 2023, 15:43

Code: Alles auswählen

{**w1, **w2}
Mit nur einem Element würde ich das machen, wenn ich in einem großen Team wäre und genau wüsste, dass sich ein Entwickler garantiert darüber tierisch aufregen würde.
Ich meinte mein Beispiel. Dort wird nur ein Iterable ausgepackt und nicht zwei kombiniert.
Code-Golf halt...