J'essaie de regrouper les chaînes binaires de certains nombres en fonction du nombre de 1 dans la chaîne.
Cela ne fonctionne pas:
s = "0 1 3 7 8 9 11 15"
numbers = map(int, s.split())
binaries = [bin(x)[2:].rjust(4, '0') for x in numbers]
one_groups = dict.fromkeys(range(5), [])
for x in binaries:
one_groups[x.count('1')] += [x]
Le dictionnaire attendu one_groups
doit être
{0: ['0000'],
1: ['0001', '1000'],
2: ['0011', '1001'],
3: ['0111', '1011'],
4: ['1111']}
Mais je reçois
{0: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
1: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
2: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
3: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
4: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111']}
Jusqu'à présent, la seule chose qui a fonctionné est si j'utilise one_groups[x.count('1')] = one_groups.get(x.count('1')) + [x]
au lieu deone_groups[x.count('1')] += [x]
Mais pourquoi en est-il ainsi? Si je me souviens bien, n'est-il pas dict[key]
censé renvoyer la valeur de ce dictionnaire, comme cela dict.get(key)
fonctionne? J'ai vu ce fil Pourquoi dict.get (key) au lieu de dict [key]? mais il n'a pas répondu à ma question pour ce cas particulier, car je sais avec certitude que le programme n'est pas destiné à obtenir leKeyError
J'ai également essayé one_groups[x.count('1')].append(x)
mais cela ne fonctionne pas non plus.
la source
get
renvoieNone
si la clé n'existe pas ou toute valeur par défaut fournie, tandis que l'opérateur d'index[]
génère une erreur si la clé n'existe pas.bin(x)[2:].rjust(4, '0')
peut être simplifié'{:0>4b}'.format(x)
.binaries
n'est pas pertinente pour la question, vous pouvez donc simplement fournir sa valeur.Réponses:
Le problème est la mutabilité:
one_groups = dict.fromkeys(range(5), [])
- cela transmet la même liste que la valeur à toutes les clés . Donc, si vous changez une valeur, vous les changez tous.C'est essentiellement la même chose que de dire:
Si vous souhaitez utiliser une nouvelle liste, vous devez le faire en boucle - soit une
for
boucle explicite soit une compréhension de dict:Cette chose "s'exécutera"
[]
(ce qui équivaut àlist()
) pour chaque clé, créant ainsi les valeurs avec des listes différentes.Pourquoi ça
get
marche? Parce que vous prenez explicitement la liste actuelle, mais+
créez une nouvelle liste de résultats. Et peu importe que ce soitone_groups[x.count('1')] = one_groups.get(x.count('1')) + [x]
ouone_groups[x.count('1')] = one_groups[x.count('1')] + [x]
- ce qui compte, c'est qu'il y en ait+
.Je sais que tout le monde dit que
a+=b
c'est justea=a+b
, mais l'implémentation peut être différente pour l'optimisation - dans le cas des listes,+=
c'est simplement.extend
parce que nous savons que nous voulons notre résultat dans la variable actuelle, donc créer une nouvelle liste serait une perte de mémoire.la source
mylist = [[] * 5] * 5
et comment l'mylist = [[] for x in range(5)] * 5
aurais résolu. Juste pour une clarification rapide, d'après ce que j'ai compris, cela se produit en raison des variables pointant vers l'adresse mémoire de cette liste vide. Cela signifie-t-il également que le problème ne se produirait pas si j'utilisais des primitives à la place?one_groups[x.count('1')] += [x]
car vous ne pouvez pas ajouter de liste à un type primitif. Une meilleure solution consiste à utiliser plutôt defaultdict.+
appelle__add__
et renvoie un nouvel objet, tandis qu'il+=
appelle__iadd__
et n'est pas obligé de renvoyer un nouvel objetLe problème est d'utiliser
one_groups = dict.fromkeys(range(5), [])
(Cela transmet la même liste que la valeur à toutes les clés. Donc, si vous changez une valeur, vous les changez toutes)
Vous pouvez utiliser ceci à la place:
one_groups = {i:[] for i in range(5)}
(Cette chose "exécutera" [] (ce qui équivaut à list ()) pour chaque clé, créant ainsi les valeurs avec des listes différentes.)
la source
Ceci est l'aide sur la
fromkeys
méthode de dict .Cela signifie que fromkeys acceptera une valeur, et même si c'est un appelable, il l'évaluera d'abord, puis attribuera cette valeur à toutes les touches dict.
Les listes sont modifiables en Python, et il affectera donc la même référence de liste vide et une modification les affectera toutes.
Utilisez plutôt defaultdict comme suit:
Cela acceptera les affectations à des clés non existantes et les valeurs seront par défaut des listes vides (dans ce cas).
la source