2010-10-05 11 views
9

Quiero crear una función para recorrer recursivamente un diccionario multidimensional, donde las dimensiones son desconocidas.diccionario multidimensional de recorrido recursivo, dimensión desconocida

Esto es lo que he encontrado hasta ahora, pero parece que no funciona correctamente. Esto imprimirá algunas claves/valores dos veces y no están en orden.

def walk_dict(d): 
    for k,v in d.items(): 
     if isinstance(v, dict): 
      walk_dict(v) 
     else: 
      print "%s %s" % (k, v) 

Aquí hay una matriz de muestras:

d = { 
     'plan_code': 'b', 
     'quantity': '1', 
     'account': { 
      'account_code': 'b', 
      'username': 'jdoe', 
      'email': '[email protected]', 
      'first_name': 'b', 
      'last_name': 'b', 
      'company_name': 'Company, LLC.', 
      'billing_info': { 
       'first_name': 'b', 
       'last_name': 'b', 
       'address1': '123 Test St', 
       'city': 'San Francisco', 
       'state': 'CA', 
       'country': 'US', 
       'zip': '94105', 
       'credit_card': { 
        'number': '1', 
        'year': '2018', 
        'month': '12', 
        'verification_value': '123', 
       }, 
      }, 
     }, 
    } 
+0

¿cuál es su pregunta? – SingleNegationElimination

Respuesta

13

No estoy seguro cuál es tu objetivo final, pero el código está haciendo lo que se supone que debe hacer. Estás viendo lo que crees que son repeticiones de elementos porque hay combos de clave/valor como 'first_name': 'b' que están dentro de 'account' y dentro de 'billing_info' dentro de 'account'. No estoy seguro de qué orden que busca, pero los diccionarios no están ordenados de modo que su función para imprimir en papel tendrá que darles un poco de orden, por ejemplo, sustituyendo la siguiente:

for k,v in d.items(): 

con

for k,v in sorted(d.items(),key=lambda x: x[0]): 

o necesitará un diccionario ordenado. También puede utilizar el módulo pprint como tal para dar una buena impresión de un diccionario:

>>> import pprint 
>>> pprint.pprint(d) 
{'account': {'account_code': 'b', 
      'billing_info': {'address1': '123 Test St', 
           'city': 'San Francisco', 
           'country': 'US', 
           'credit_card': {'month': '12', 
               'number': '1', 
               'verification_value': '123', 
               'year': '2018'}, 
           'first_name': 'b', 
           'last_name': 'b', 
           'state': 'CA', 
           'zip': '94105'}, 
      'company_name': 'Company, LLC.', 
      'email': '[email protected]', 
      'first_name': 'b', 
      'last_name': 'b', 
      'username': 'jdoe'}, 
'plan_code': 'b', 
'quantity': '1'} 

Sin embargo, no estoy totalmente seguro de lo que su objetivo final es aquí. Además, te faltan las claves cuando los valores son diccionarios. He modificado el código para hacer algo similar a lo que pprint hace en lo siguiente:

def walk_dict(d,depth=0): 
    for k,v in sorted(d.items(),key=lambda x: x[0]): 
     if isinstance(v, dict): 
      print (" ")*depth + ("%s" % k) 
      walk_dict(v,depth+1) 
     else: 
      print (" ")*depth + "%s %s" % (k, v) 

el cual por su ejemplo rendimientos dict:

>>> walk_dict(d) 
account 
    account_code b 
    billing_info 
    address1 123 Test St 
    city San Francisco 
    country US 
    credit_card 
     month 12 
     number 1 
     verification_value 123 
     year 2018 
    first_name b 
    last_name b 
    state CA 
    zip 94105 
    company_name Company, LLC. 
    email [email protected] 
    first_name b 
    last_name b 
    username jdoe 
plan_code b 
quantity 1 
2

Esto se imprime la clave, pares de valores correctamente. ¿Puedes indicar qué datos se repiten? No puede haber confusión sobre la base de los datos anteriores como estas teclas:

'first_name': 'b', 
'last_name': 'b', 

son parte de dos diccionarios - 'cuenta' y 'billing_info'. Entonces aparecerán dos veces en salida.

Además, si desea algún tipo de orden en el que los diccionarios K, V debe conseguir impresa uso ordenado Diccionarios

+0

Acabo de agarrar ese dict y no noté la repetición. Pensé que estaba haciendo algo mal. Gracias por señalar eso. – imns

0

su código funciona bien perfecto, que hace exactamente lo que le dijo a.

Las únicas repeticiones que veo en la salida son first_name y last_name que de hecho se definen dos veces (en diferentes diccionarios).

En cuanto a 'fuera de servicio' Es un diccionario, no tiene un orden garantizado. bueno, tal vez sí, pero se basaría en la representación interna, en la que no deberías confiar.

Lo que debe hacer es ordenar los datos en la forma en que desea que salga. También es posible que desee imprimir el valor de clave del diccionario secundario para facilitar la comprensión de la salida.

1

Como Justin Peelmentions, pprint.pprint probablemente haga lo que quiera.

Creo que el problema con su código es que se debe a imprimir primero la llave antes de manera recursiva, es decir, cambiar

if isinstance(v, dict): 
     walk_dict(v) 

a

if isinstance(v, dict): 
     print k 
     walk_dict(v) 

Aunque en cualquier caso, va a parecer bastante confuso a menos que agregue una sangría y tal.

Este tipo de cosas es bastante complicado; mira el código para pprint si quieres obtener algunas ideas.

0

En Python, los diccionarios están indexados por claves. Las claves pueden ser de cualquier tipo inmutable, como una cadena o número. A menos que las claves estén ordenadas, siempre se devolverán en un orden arbitrario. Debido a este hecho, su walk_dict está imprimiendo resultados aparentemente aleatorios.

Aquí hay un ejemplo de walk_dict que imprime todas las claves y valores. He ordenado las claves en cada nivel del diccionario. Además, imprimí cada clave. Su código no imprimió una clave antes de que recursó. Finalmente, he agregado relleno de cuerdas para enfatizar cada nivel del diccionario. Los doctests están pasando. Espero que esto te ayude a construir tu función final.

import doctest 


def walk_dict(seq, level=0): 
    """Recursively traverse a multidimensional dictionary and print all 
    keys and values. 

    >>> d = {'dog': 'dusty', 'cat': 'fluffy', 'bird': 'chirpy'} 
    >>> walk_dict(d) 
    bird chirpy 
    cat fluffy 
    dog dusty 
    >>> d = {'location': 'home', 'animals':{'dog': 'dusty', 'cat': 'fluffy', 'bird': 'chirpy'}} 
    >>> walk_dict(d) 
    animals 
     bird chirpy 
     cat fluffy 
     dog dusty 
    location home 
    >>> d = {'location': 'home', 'animals':{'dog': 'dusty', 'cat': 'fluffy', 'bird': {'name':'chirpy', 'color':'blue'}}} 
    >>> walk_dict(d) 
    animals 
     bird 
     color blue 
     name chirpy 
     cat fluffy 
     dog dusty 
    location home 
    >>> d = { \ 
      'plan_code': 'b', \ 
      'quantity': '1', \ 
      'account': { \ 
       'account_code': 'b', \ 
       'username': 'jdoe', \ 
       'email': '[email protected]', \ 
       'first_name': 'b', \ 
       'last_name': 'b', \ 
       'company_name': 'Company, LLC.', \ 
       'billing_info': { \ 
        'first_name': 'b', \ 
        'last_name': 'b', \ 
        'address1': '123 Test St', \ 
        'city': 'San Francisco', \ 
        'state': 'CA', \ 
        'country': 'US', \ 
        'zip': '94105', \ 
        'credit_card': { \ 
         'number': '1', \ 
         'year': '2018', \ 
         'month': '12', \ 
         'verification_value': '123', \ 
        }, \ 
       }, \ 
      }, \ 
     } 
    >>> walk_dict(d) 
    account 
     account_code b 
     billing_info 
     address1 123 Test St 
     city San Francisco 
     country US 
     credit_card 
      month 12 
      number 1 
      verification_value 123 
      year 2018 
     first_name b 
     last_name b 
     state CA 
     zip 94105 
     company_name Company, LLC. 
     email [email protected] 
     first_name b 
     last_name b 
     username jdoe 
    plan_code b 
    quantity 1 
    """ 
    items = seq.items() 
    items.sort() 
    for v in items: 
     if isinstance(v[1], dict): 
      # Print the key before make a recursive call 
      print "%s%s" % (" " * level, v[0]) 
      nextlevel = level + 1 
      walk_dict(v[1], nextlevel) 
     else: 
      print "%s%s %s" % (" " * level, v[0], v[1]) 


if __name__ == '__main__': 
    doctest.testmod() 
3

>>> import json

>>> print json.dumps(d, indent=4)

+1

En mi caso, necesito hacer esto precisamente porque 'json.dumps' no puede manejar algunos de los objetos en la estructura. – OrangeDog

+0

La librería 'jsonpickle' hace un trabajo sorprendentemente bueno al representar los tipos de objetos' json' chokes on - inténtalo. –

1

Aquí es una variación en la respuesta aceptada por Justin Peel que devuelve su resultado como un OrderedDict en lugar de imprimir el resultado.

from collections import OrderedDict 

def sort_by_keys(dct,): 
    new_dct = OrderedDict({}) 
    for key, val in sorted(dct.items(), key=lambda (key, val): key): 
     if isinstance(val, dict): 
      new_dct[key] = sort_by_keys(val) 
     else: 
      new_dct[key] = val 
    return new_dct 
Cuestiones relacionadas