2011-01-03 20 views
14

¿Cómo cuento la cantidad de subelementos en un diccionario anidado de la manera más eficiente posible? La función len() no funciona como yo inicialmente esperaba que:¿Cómo contar todos los elementos en un diccionario anidado?

>>> food_colors = {'fruit': {'orange': 'orange', 'apple': 'red', 'banana': 'yellow'}, 'vegetables': {'lettuce': 'green', 'beet': 'red', 'pumpkin': 'orange'}} 
>>> len(food_colors) 
2 
>>> 

¿Qué pasa si en realidad quiero contar el número de subelementos? (Por ejemplo, el resultado esperado es "6") ¿Hay una forma mejor de hacerlo en lugar de recorrer cada elemento y sumar la cantidad de subelementos? En esta aplicación en particular, tengo que contar aproximadamente cinco millones de subelementos y cada ciclo de reloj cuenta.

+1

Lo que está mal con 'len (food_colors [ 'fruta']) + len (food_colors [ 'verduras'])'? –

Respuesta

13

¿Se garantiza que cada tecla de nivel superior tenga un valor de diccionario y que ninguna clave de segundo nivel tenga un diccionario? Si es así, esto va a ir tan rápido como se puede esperar:

sum(len(v) for v in food_colors.itervalues()) 

si la estructura de datos es más complicado, se necesita más código, por supuesto. No estoy al tanto de ningún intrínseco para hacer caminatas profundas de estructura de datos.

1

¿Desea solamente los niños inmediatos? Si es así, este es probablemente el mejor:

sum(len(x) for x in fc.values()) 
1

Los sub-elementos son objetos distintos, no hay otra relación con el uso que va a ser fundamentalmente más rápido que la iteración en ellos - aunque hay un montón de maneras de hacer eso (utilizando map , o .values(), por ejemplo) que variará en rendimiento, lo suficiente como para que probablemente desee usar timeit para compararlos.

Si contarlas es importante para su aplicación, considere hacer algunas cosas para hacer que más fácil:

  • contarlos a medida que construye la estructura de datos
  • en lugar de anidados dict s, considere una memoria de sqlite mesa, utilizando connect(":memory:") (esto podría ralentizar otras operaciones, o los hacen más compleja, pero la desventaja es digno de consideración.)
1
c = sum([len(i) for i in fruit_colors.values() ]) 
+1

Los corchetes son innecesarios y en este caso probablemente disminuyan la velocidad. – zwol

4

Para su pregunta específica, sólo puede utilizar este:

>>> d={'fruit': 
     {'orange': 'orange', 'apple': 'red', 'banana': 'yellow'}, 
     'vegetables': 
     {'lettuce': 'green', 'beet': 'red', 'pumpkin': 'orange'}} 
>>> len(d) 
2   # that is 1 reference for 'fruit' and 1 for 'vegetables' 
>>> len(d['fruit']) 
3   # 3 fruits listed... 
>>> len(d['vegetables']) 
3   # you thought of three of those... 
>>> len(d['fruit'])+len(d['vegetables']) 
6 

Aunque puede utilizar las distintas herramientas que Python tiene que contar con los elementos en este diccionario trivial, lo más interesante y productivo es pensar en el estructura de los datos en primer lugar.

Las estructuras de datos básicas de Python son lists, sets, tuples, and dictionaries. Cualquiera de estas estructuras de datos puede 'contener', por referencia, cualquier versión anidada de sí mismo o de otras estructuras de datos.

Esta lista es una nested list:

>>> l = [1, [2, 3, [4]], [5, 6]] 
>>> len(l) 
3 
>>> l[0] 
1 
>>> l[1] 
[2, 3, [4]] 
>>> l[2] 
[5, 6] 

El primer elemento es el número entero 1. Elementos 1 y 2 son listas mismos. Lo mismo puede ser cierto de cualquier otra estructura de datos básica de Python. Estos son recursive data structures.Puede imprimir con pprint

Si organiza su diccionario un poco mejor, es más fácil de extraer información de ella con las herramientas más simples de Python:

>>> color='color' 
>>> family='family' 
>>> sensation='sensation' 
>>> good_things={ 
      'fruit': 
      { 
       'orange': 
        { 
        color: 'orange', 
        family: 'citrus', 
        sensation: 'juicy' 
        }, 
       'apple': 
        { 
        color: ['red','green','yellow'], 
        family:'Rosaceae', 
        'sensation': 'woody' 
        }, 
       'banana': 
        { 
        color: ['yellow', 'green'], 
        family: 'musa', 
        sensation: 'sweet' 
        } 
      }, 
      'vegatables': 
      { 
       'beets': 
        { 
        color: ['red', 'yellow'], 
        family: 'Chenopodiaceae', 
        sensation: 'sweet' 
        }, 
       'broccoli': 
        { 
        color: 'green', 
        family: 'kale', 
        sensation: 'The butter you put on it', 
        } 
      } 
     }  

Ahora las consultas en que los datos tienen más sentido:

>>> len(good_things) 
2      # 2 groups: fruits and vegetables 
>>> len(good_things['fruit']) 
3      # three fruits cataloged 
>>> len(good_things['vegetables']) 
2      # I can only think of two vegetables... 
>>> print good_things['fruit']['apple'] 
{'color': ['red', 'green', 'yellow'], 'sensation': 'woody', 'family': 'Rosaceae'} 
>>> len(good_things['fruit']['apple']['color']) 
3      # apples have 3 colors 
1

Puede hacer esto con una función recursiva.

>>> x 
{'a': 1, 'b': 2, 'c': 3, 'd': {'I': 1, 'II': 2, 'III': 3}, 'e': 5} 
>>> def test(d): 
... cnt = 0 
... for e in d: 
...  if type(d[e]) is dict: 
...  cnt += test(d[e]) 
...  else: 
...  cnt += 1 
... return cnt 
... 
>>> test(x) 
7 
0

diccionarios anidados de profundidad arbitraria Por:

def num_elements(x): 
    if isinstance(x, dict): 
    return sum([num_elements(_x) for _x in x.values()]) 
    else: return 1 
Cuestiones relacionadas