liste als key in dictionary

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.
blutigeranfaenger
User
Beiträge: 65
Registriert: Dienstag 4. März 2014, 12:04

Hallo zusammen,
ich möchte gerne zwei listen zu einem dictionary vereinen:

Code: Alles auswählen

#!/usr/bin/env python3
l_a = [ [0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5]]
l_b = [1,2,3]
mydict = dict(zip(l_a,l_b))
Das klappt so nicht, ich weiß, eine Liste kann kein key in einem Wörterbuch sein.
Gibt es dennoch einen Weg, das gewünschte Ziel zu erreichen und wie könnte dieser Weg gehen?
Danke für eure Tipps!
Benutzeravatar
Dennis89
User
Beiträge: 1215
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

so?

Code: Alles auswählen

Python 3.10.7 (main, Sep  7 2022, 00:00:00) [GCC 12.2.1 20220819 (Red Hat 12.2.1-1)] on linux
l_a = [ [0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 2, 5]]
l_b = [1,2,3]
list_to_dic = {}
for index, key in enumerate(l_b):
    list_to_dic[key] = l_a[index]
    
print(list_to_dic)
{1: [0, 1, 2, 3], 2: [0, 1, 2, 4], 3: [0, 1, 2, 5]}
Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du kannst die Listen zu Tupeln machen, die gehen durch ihre immutability als Keys.
blutigeranfaenger
User
Beiträge: 65
Registriert: Dienstag 4. März 2014, 12:04

Ja, super, das hat funktioniert, vielen Dank!
Benutzeravatar
Dennis89
User
Beiträge: 1215
Registriert: Freitag 11. Dezember 2020, 15:13

Damit der Vorschlag von @__deets__ auch noch hier steht:

Code: Alles auswählen

l_a = [(0, 1, 2, 3), (0, 1, 2, 4), (0, 1, 2, 5)]
l_b = [1, 2, 3]
list_to_dict = dict(zip(l_b, l_a))
print(list_to_dict)
{1: (0, 1, 2, 3), 2: (0, 1, 2, 4), 3: (0, 1, 2, 5)}
War das so gemeint?

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nein. Du hast dir hier die Freiheit genommen, Schluessel und Werte umzudrehen. Das ist etwas komplett anderes, und loest die Aufgabe nicht. Egal, ob dann die Werte Tupel statt Listen sind.

Es geht darum, das die Schluessel Tupel sein muessen, weil es aus technischen und logischen Gruenden nicht moeglich und sinnvoll ist, vereaenderbare Schluessel zuzulassen. Und natuerlich muessen die Schluessel nach wie vor prinzipiell gleich sein, ich will nicht nach 1 schauen, ich will [0, 1, 2, 3] nachschlagen.
Benutzeravatar
Dennis89
User
Beiträge: 1215
Registriert: Freitag 11. Dezember 2020, 15:13

Achsoooo, da habe ich den Eingangspost falsch verstanden und dann war ja schon mein erster Post Mist. :oops:

Danke für die Verbesserung.

Grüße
Dennis

Edit:
Du hast dir hier die Freiheit genommen, Schluessel und Werte umzudrehen.
So lassen sich Probleme einfacher lösen :D
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
DeaD_EyE
User
Beiträge: 1038
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Die keys eines dicts müssen immutable sein. Ein set kann man nicht als key nehmen, aber ein frozenset geht. Eine Tuple geht auch, da sie nicht veränderbar ist.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Tuple sind ein Grenzfall: sollten die Inhalte eines Tuple mutable sein, dann geht es gleichfalls nicht.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Grenzfall wuerde ich das jetzt nicht nennen. Der Schluessel muss einfach transitiv immutable sein. Letztlich folgt das aus der Notwendigkeit fuer Schluessel vergleichbar zu sein. Und der ==-Operator ist fuer Tupel elementweise definiert, gleiches gilt fuer Listen. Womit ein Tupel mit einer Liste als Element nicht zulaessig ist, denn die Liste liesse sich ja nachtraeglich veraendern, und waere nicht mehr gleich.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Das meine ich ja: der Datentyp Tuple selbst is immutable; dies muss aber auch für den Value des Tuples gelten, damit es als Key verwendbar ist.
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

Es geht letztlich nicht um mutability sondern um hashability. Also mutable darf es schon sein, solange es auch hashable ist.

Mit selbst definierten Klassen kann man das durchaus machen. Es ist nach meiner Erfahrung aber nur selten sinnvoll.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Hashable allein genügt nicht, es muss auch stets der gleiche hash-Wert erzeugt werden. Daher scheiden Datentypen mit mutablen Inhalten als Keys aus.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1038
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

kbr hat geschrieben: Donnerstag 27. Oktober 2022, 16:57 Tuple sind ein Grenzfall: sollten die Inhalte eines Tuple mutable sein, dann geht es gleichfalls nicht.
Stimmt. Auf die Idee, so etwas zu machen, bin ich noch nie gekommen.
Dach höchste aller Gefühle: Tuple als Key, wobei die Tuple ausschließlich einen Datentypen enthält (int z.B.).

Hier mal etwas anderes komisches, dass halb funktioniert.
Der Liste wird trotz einer Exception das Objekt hinzugefügt (== list.extend).

Code: Alles auswählen

tup = (1, 2, [])
tup[-1] += [1]
TypeError: 'tuple' object does not support item assignment

Danach ist das letzte Element: [1]
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

kbr hat geschrieben: Donnerstag 27. Oktober 2022, 19:06 Hashable allein genügt nicht, es muss auch stets der gleiche hash-Wert erzeugt werden. Daher scheiden Datentypen mit mutablen Inhalten als Keys aus.
Das ist nicht korrekt. Um key in einem dictionary zu sein, reicht es aus, wenn hash() einen Wert liefert (d.h. wenn man __hash__() geeignet implementiert). Wenn sich der hash-Wert ändert, findet man den Schlüssel nicht mehr, das sollte man also auf keinen Fall tun. Der hash-Wert darf also nicht von den mutablen Teilen abhängen.

Ich habe z.B. schon gesehen, dass __hash__ die id zurückgibt.
Man könnte aber auch den hash von zwei Attributen verwenden, und alle anderen Attribute könnten dann veränderbar sein.
Oder der hash ist zwar veränderlich, aber die Objekte werden nicht verändert, während sie in ein set gesteckt werden oder so.

Wichtig: Aus Gleichheit von Objekten muss immer auch die Gleichheit der hashes folgen. (Laut Doku die einzige erforderliche Eigenschaft von __hash__().)
https://docs.python.org/3/reference/dat ... t.__hash__
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

DeaD_EyE hat geschrieben: Freitag 28. Oktober 2022, 13:39

Code: Alles auswählen

tup = (1, 2, [])
tup[-1] += [1]
TypeError: 'tuple' object does not support item assignment

Danach ist das letzte Element: [1]
Das liegt am augmented assignment. Das macht die Liste größer, und dann nochmal die Zuweisung, "assignment" eben, auch wenn es "augmented" ist. Verwirrend, aber hat Methode :-)
In Langform:

Code: Alles auswählen

tup = (1, 2, [])
# Langform von tup[-1] += [1]
temp = tup[-1]
temp += [1]  # geht noch
tup[-1] = temp  # TypeError
Benutzeravatar
__blackjack__
User
Beiträge: 13241
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@bords0: Das ist im Grunde doch korrekt. Du schreibst ja selbst das 🔑, deren Hashwert sich ändert, dann nicht mehr wiedergefunden werden. Um das sinnvoll als 🔑 verwenden zu können, darf sich der Hashwert nicht ändern, denn sinnvoll wäre ja schon, das man 🔑 auch wiederfindet. 🙂
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
Benutzeravatar
__blackjack__
User
Beiträge: 13241
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ist natürlich ein Implementierungsdetail, aber die Implementierung von `object.__hash__()` ist nahe dran die ID als Hash-Wert zu liefern:

Code: Alles auswählen

In [221]: a = object()

In [222]: hex(id(a))
Out[222]: '0x7f5d2454d570'

In [223]: hex(hash(a))
Out[223]: '0x7f5d2454d57'
Der Hash-Wert ist die ID um 4 Bits nach rechts verschoben. Und die ID (ebenfalls Implementierungsdetail) ist die Speicheradresse. Ich vermute mal Objekte sind mittlerweile mindestens 16 Bytes gross. Jup:

Code: Alles auswählen

In [224]: a.__sizeof__()
Out[224]: 16
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
Sirius3
User
Beiträge: 17826
Registriert: Sonntag 21. Oktober 2012, 17:20

@DeaD_EyE: das Assignment ist wichtig, denn wenn man

Code: Alles auswählen

werte = [1, 2, 3]
werte[2] += 1
möchte man ja, dass 4 in der Liste steht, aber das Objekt 3 ist unveränderlich, += muß also ein neues Objekt zurückliefern.
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

__blackjack__ hat geschrieben: Freitag 28. Oktober 2022, 13:58 @bords0: Das ist im Grunde doch korrekt. Du schreibst ja selbst das 🔑, deren Hashwert sich ändert, dann nicht mehr wiedergefunden werden. Um das sinnvoll als 🔑 verwenden zu können, darf sich der Hashwert nicht ändern, denn sinnvoll wäre ja schon, das man 🔑 auch wiederfindet. 🙂
"Mutable Inhalte" ist nicht das gleiche wie "veränderlicher Hashwert".

Natürlich sollte man den Hashwert nicht ändern, wenn man den alten noch braucht.
Antworten