2011-01-03 6 views
14

Как подсчитать количество подэлементов во вложенном словаре наиболее эффективным способом? Функция Len() не работает, как я изначально ожидал, что это:Как подсчитать все элементы во вложенном словаре?

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

Что делать, если я на самом деле хочу, чтобы подсчитать количество подэлементов? (например, ожидаемый результат равен «6»). Есть ли лучший способ сделать это, а не цикл через каждый элемент и суммирование количества подэлементов? В этом конкретном приложении у меня есть около пяти миллионов подэлементов для подсчета и подсчета каждого такта.

+1

Что с 'LEN (food_colors [ 'плод']) + Len (food_colors [ 'овощи'])'? –

ответ

13

Гарантировано, что каждый ключ верхнего уровня имеет словарь как его значение и что ни один ключ второго уровня не имеет словаря? Если да, то это будет так быстро, как вы можете надеяться:

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

Если структура данных является более сложным, то потребуется больше кода, конечно. Я не осведомлен о каких-либо попытках делать глубокие движения структуры данных.

1

Хотите ли вы только детей? Если да, то это, вероятно, лучше всего:

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

Подэлементов являются отдельными объектами, нет никаких других отношений, чтобы использовать это будет существенно быстрее, чем итерация над ними - хотя есть много способов сделать это (используя map , или .values(), например), которые будут отличаться по производительности, достаточно того, что вы, вероятно, захотите использовать timeit, чтобы сравнить их.

Если считать их важно для вашего приложения, рассмотреть возможность сделать некоторые вещи, чтобы сделать это проще:

  • сосчитать их, как вы строите Структура данных
  • вместо вложенных dict с, рассмотрим в памяти sqlite стол, используя connect(":memory:") (это может замедлить другие операции, или сделать их более сложными, но компромисс стоит подумать.)
1
c = sum([len(i) for i in fruit_colors.values() ]) 
+1

Квадратные скобки не нужны и в этом случае, вероятно, замедляют работу. – zwol

4

Для вашего конкретного вопроса, то вы можете просто использовать это:

>>> 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 

В то время как вы можете использовать различные инструменты, которые питон количество элементов в этом тривиальном словаре, тем более интересная и продуктивная вещь думать о структура данных в первую очередь.

Основные структуры данных Python: lists, sets, tuples, and dictionaries. Любая из этих структур данных может «удерживать» по ссылке любую вложенную версию себя или других структур данных.

Этот список nested list:

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

Первый элемент представляет собой целое число 1. Элементы 1 и 2 являются сами списки. То же самое можно сказать и о любой другой из основных структур данных Python. Это recursive data structures.Вы можете распечатать их с pprint

Если вы организовать свой словарь немного лучше, легче извлечь из него информацию с простейшими инструментами языка 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', 
        } 
      } 
     }  

Теперь запросы к этим данным больше смысла:

>>> 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

Вы можете сделать это с помощью рекурсивной функции.

>>> 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

Для произвольной глубины вложенности словарях:

def num_elements(x): 
    if isinstance(x, dict): 
    return sum([num_elements(_x) for _x in x.values()]) 
    else: return 1 
Смежные вопросы