Estou tentando agrupar as cadeias binárias de certos números com base em quantos 1s existem na cadeia.
Isso não funciona:
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]
O dicionário esperado one_groups
precisa ser
{0: ['0000'],
1: ['0001', '1000'],
2: ['0011', '1001'],
3: ['0111', '1011'],
4: ['1111']}
Mas eu entendo
{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']}
Até agora, a única coisa que funcionou é se eu usar em one_groups[x.count('1')] = one_groups.get(x.count('1')) + [x]
vez deone_groups[x.count('1')] += [x]
Mas porque é isso? Se bem me lembro, não dict[key]
deveria retornar o valor desse dicionário, semelhante a como dict.get(key)
funciona? Eu já vi esse tópico Por que dict.get (key) em vez de dict [key]? mas não respondeu à minha pergunta para esse caso em particular, pois tenho certeza de que o programa não pretende obter oKeyError
Eu também tentei, one_groups[x.count('1')].append(x)
mas isso também não funciona.
python
dictionary
SpectraXCD
fonte
fonte
get
retorneNone
se a chave não existir ou qualquer valor padrão fornecido, enquanto o operador de índice[]
gerará um erro se a chave não existir.bin(x)[2:].rjust(4, '0')
pode ser simplificado para'{:0>4b}'.format(x)
.binaries
não é relevante para a pergunta, portanto, você pode apenas fornecer seu valor.Respostas:
O problema é mutabilidade:
one_groups = dict.fromkeys(range(5), [])
- isso passa a mesma lista que o valor para todas as chaves . Portanto, se você alterar um valor, alterará todos eles.É basicamente o mesmo que dizer:
Se você quiser usar uma nova lista, precisará fazê-lo em um loop - um
for
loop explícito ou em uma compreensão de ditado:Essa coisa será "executada"
[]
(que é igual alist()
) para cada chave, criando os valores com listas diferentes.Por que
get
funciona? Porque você pega explicitamente a lista atual, mas+
cria uma nova lista de resultados. E não importa se éone_groups[x.count('1')] = one_groups.get(x.count('1')) + [x]
ouone_groups[x.count('1')] = one_groups[x.count('1')] + [x]
- o que importa é que existe+
.Eu sei como todo mundo diz que
a+=b
é justoa=a+b
, mas a implementação pode ser diferente para otimização - no caso de listas,+=
é apenas.extend
porque sabemos que queremos nosso resultado na variável atual, portanto, criar uma nova lista seria desperdício de memória.fonte
mylist = [[] * 5] * 5
e como amylist = [[] for x in range(5)] * 5
teria corrigido. Apenas para esclarecimentos rápidos, pelo que entendi, isso acontece devido às variáveis que apontam para o endereço de memória dessa lista vazia. Isso também significa que o problema não ocorreria se eu usasse primitivas?one_groups[x.count('1')] += [x]
porque você não pode adicionar uma lista a um tipo primitivo. Uma solução melhor é usar o defaultdict.+
chamadas__add__
e retorna um novo objeto, enquanto+=
as chamadas__iadd__
, e não é necessário para retornar um novo objetoO problema está usando
one_groups = dict.fromkeys(range(5), [])
(Isso passa a mesma lista que o valor para todas as chaves. Portanto, se você alterar um valor, alterará todas elas)
Você pode usar isso:
one_groups = {i:[] for i in range(5)}
(Essa coisa "executará" [] (que é igual a list ()) para cada chave, tornando os valores com listas diferentes.)
fonte
Esta é a ajuda no
fromkeys
método do dict .Isso indica que fromkeys aceitará um valor e, mesmo que seja possível chamar, avaliará primeiro e depois atribuirá esse valor a todas as chaves dict.
As listas são mutáveis no Python e, portanto, atribuirá a mesma referência de lista vazia e uma alteração afetará todas elas.
Use defaultdict em vez disso:
Isso aceitará atribuições para chaves não existentes e os valores serão padronizados para listas vazias (nesse caso).
fonte