for k, v in d.iteritems():
if type(v) is dict:
for t, c in v.iteritems():
print "{0} : {1}".format(t, c)
Estou tentando percorrer um dicionário e imprimir todos os pares de valores-chave onde o valor não é um dicionário aninhado. Se o valor for um dicionário, quero ir até ele e imprimir seus pares de valores-chave ... etc. Qualquer ajuda?
EDITAR
Que tal agora? Ele ainda imprime apenas uma coisa.
def printDict(d):
for k, v in d.iteritems():
if type(v) is dict:
printDict(v)
else:
print "{0} : {1}".format(k, v)
Caso de Teste Completo
Dicionário:
{u'xml': {u'config': {u'portstatus': {u'status': u'good'}, u'target': u'1'},
u'port': u'11'}}
Resultado:
xml : {u'config': {u'portstatus': {u'status': u'good'}, u'target': u'1'}, u'port': u'11'}
python
dictionary
Takkun
fonte
fonte
dict
um nome de variável. Nunca faça isso (é por isso que falha).Respostas:
Como disse Niklas, você precisa de recursão, ou seja, você deseja definir uma função para imprimir seu dicionário, e se o valor for um dicionário, você deseja chamar sua função de impressão usando este novo dicionário.
Algo como :
fonte
Existem problemas potenciais se você escrever sua própria implementação recursiva ou o equivalente iterativo com pilha. Veja este exemplo:
No sentido normal, o dicionário aninhado será uma árvore n-nária como a estrutura de dados. Mas a definição não exclui a possibilidade de uma borda cruzada ou mesmo uma borda posterior (portanto, não é mais uma árvore). Por exemplo, aqui key2.2 abrange o dicionário de key1 , key2.3 aponta para todo o dicionário (borda posterior / ciclo). Quando houver uma borda posterior (ciclo), a pilha / recursão será executada infinitamente.
Se você imprimir este dicionário com esta implementação de Scharron
Você veria este erro:
O mesmo acontece com a implementação do remetente .
Da mesma forma, você obtém um loop infinito com esta implementação de Fred Foo :
No entanto, o Python realmente detecta ciclos no dicionário aninhado:
"{...}" é onde um ciclo é detectado.
Conforme solicitado pela Moondra, esta é uma forma de evitar ciclos (DFS):
fonte
def myprint(d): stack = d.items() visited = set() while stack: k, v = stack.pop() if isinstance(v, dict): if k not in visited: stack.extend(v.iteritems()) else: print("%s: %s" % (k, v)) visited.add(k)
list(d.items())
asd.items()
retorna uma visualização, não uma lista, e use emv.items()
vez dev.iteritems()
Como a
dict
é iterável, você pode aplicar a fórmula iterável de contêiner aninhado clássica a esse problema com apenas algumas pequenas alterações. Esta é uma versão do Python 2 (veja a 3 abaixo):Teste:
No Python 2, pode ser possível criar um personalizado
Mapping
que se qualifique como um,Mapping
mas não contenhaiteritems
; nesse caso, haverá falha. Os documentos não indicam queiteritems
é necessário para umMapping
; por outro lado, a fonte fornece aosMapping
tipos umiteritems
método. Então, para customizarMappings
, herde decollections.Mapping
explicitamente apenas no caso.No Python 3, há uma série de melhorias a serem feitas. A partir do Python 3.3, classes básicas abstratas estão presentes
collections.abc
. Eles permanecem dentrocollections
também para compatibilidade com versões anteriores, mas é melhor ter nossas classes básicas abstratas juntas em um namespace. Então, isso importaabc
decollections
. Python 3.3 também adicionayield from
, que é projetado exatamente para esse tipo de situação. Este não é um açúcar sintático vazio; pode levar a um código mais rápido e interações mais sensíveis com corrotinas .fonte
isinstance(item, collections.Iterable)
não há garantia parahasattr(item, "iteritems")
. Verificarcollections.Mapping
é melhor.Iterable
tornaria essa solução mais generalizada, esquecendo que, obviamente, iteráveis não necessariamente têmiteritems
.yield from
sintaxe.Solução iterativa alternativa:
fonte
list
) por umadeque
ou mesmo uma fila de prioridade.Uma versão ligeiramente diferente que escrevi que mantém o controle das chaves ao longo do caminho para chegar lá
Em seus dados, será impresso
Também é fácil modificá-lo para rastrear o prefixo como uma tupla de chaves, em vez de uma string, se for necessário.
fonte
Aqui está a maneira pítônica de fazer isso. Esta função permitirá que você percorra o par de valores-chave em todos os níveis. Não salva tudo na memória, mas sim percorre o dicionário enquanto você o percorre
Impressões
fonte
Solução iterativa como alternativa:
fonte
O(depth)
para a solução recursiva. O mesmo se aplica a esta versão, se estou pensando corretamente).iters
como uma pilha explícita, então o consumo de memória Big-O é o mesmo, ou estou perdendo alguma coisa?Uma solução alternativa para trabalhar com listas baseada na solução de Scharron
fonte
Estou usando o código a seguir para imprimir todos os valores de um dicionário aninhado, levando em consideração onde o valor pode ser uma lista contendo dicionários. Isso foi útil para mim ao analisar um arquivo JSON em um dicionário e precisar verificar rapidamente se algum de seus valores é
None
.Resultado:
fonte
Aqui está uma versão modificada da resposta de Fred Foo para Python 2. Na resposta original, apenas o nível mais profundo de aninhamento é gerado. Se você produzir as chaves como listas, poderá mantê-las para todos os níveis, embora para referenciá-las seja necessário referenciar uma lista de listas.
Esta é a função:
Para fazer referência às chaves:
para um dicionário de três níveis.
Você precisa saber o número de níveis antes de acessar várias chaves e o número de níveis deve ser constante (pode ser possível adicionar um pequeno script para verificar o número de níveis de aninhamento ao iterar por meio de valores, mas eu não ainda olhou para isso).
fonte
Acho essa abordagem um pouco mais flexível, aqui você apenas fornece uma função de gerador que emite pares de chave e valor e pode ser facilmente estendida para também iterar em listas.
Então você pode escrever sua própria
myprint
função e imprimir esses pares de valores-chave.Um teste:
Resultado:
Eu testei isso no Python 3.6.
fonte
Essas respostas funcionam para apenas 2 níveis de subdicionários. Para mais experimente isto:
fonte