Existe uma maneira de ter um defaultdict(defaultdict(int))
para fazer o seguinte código funcionar?
for x in stuff:
d[x.a][x.b] += x.c_int
d
precisa ser construído ad-hoc, dependendo x.a
e x.b
elementos.
Eu poderia usar:
for x in stuff:
d[x.a,x.b] += x.c_int
mas então eu não seria capaz de usar:
d.keys()
d[x.a].keys()
python
collections
Jonathan
fonte
fonte
Respostas:
Sim como isso:
O argumento de a
defaultdict
(neste caso élambda: defaultdict(int)
) será chamado quando você tentar acessar uma chave que não existe. O valor de retorno será definido como o novo valor dessa chave, o que significa que, no nosso caso, o valor ded[Key_doesnt_exist]
serádefaultdict(int)
.Se você tentar acessar uma chave deste último padrão, ou seja,
d[Key_doesnt_exist][Key_doesnt_exist]
ele retornará 0, que é o valor de retorno do argumento do último padrão, ou sejaint()
.fonte
defaultdict
(neste caso élambda : defaultdict(int)
) será chamado quando você tentar acessar uma chave que não existe e o valor de retorno dela será definido como o novo valor dessa chave, que significa no nosso caso, o valor ded[Key_dont_exist]
serádefaultdict(int)
e, se você tentar acessar uma chave deste último padrão, ou seja,d[Key_dont_exist][Key_dont_exist]
ele retornará 0, que é o valor de retorno do argumento do último ,defaultdict
ou sejaint()
, espero que isso tenha sido útil.defaultdict
deve ser uma função.defaultdict(int)
é um dicionário, enquantolambda: defaultdict(int)
é uma função que retorna um dicionário.defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
O parâmetro para o construtor defaultdict é a função que será chamada para a construção de novos elementos. Então, vamos usar um lambda!
Desde o Python 2.7, há uma solução ainda melhor usando o Counter :
Alguns recursos de bônus
Para obter mais informações, consulte PyMOTW - Coleções - tipos de dados Container e documentação do Python - coleções
fonte
d = defaultdict(lambda : Counter())
vez ded = defaultdict(lambda : defaultdict(int))
abordar especificamente o problema como originalmente colocado.d = defaultdict(Counter())
sem necessidade de um lambda neste casoCounter
objeto. Ou seja:d = defaultdict(Counter)
Acho um pouco mais elegante de usar
partial
:Claro, isso é o mesmo que um lambda.
fonte
Para referência, é possível implementar um
defaultdict
método genérico de fábrica aninhada através de:A profundidade define o número de dicionário aninhado antes que o tipo definido em
default_factory
seja usado. Por exemplo:fonte
ndd = nested_defaultdict(dict) .... ndd['a']['b']['c']['d'] = 'e'
jogaKeyError: 'b'
depth=0
, que nem sempre é desejado se a profundidade for desconhecida no momento da chamada. Facilmente corrigível, adicionando uma linhaif not depth: return default_factory()
, na parte superior da função, embora haja provavelmente uma solução mais elegante.As respostas anteriores abordaram como criar dois níveis ou n níveis
defaultdict
. Em alguns casos, você deseja um infinito:Uso:
fonte
Outros responderam corretamente à sua pergunta de como fazer o seguinte:
Uma alternativa seria usar tuplas para chaves:
O bom dessa abordagem é que ela é simples e pode ser facilmente expandida. Se você precisar mapear três níveis de profundidade, use uma tupla de três itens para a chave.
fonte