Как подсчитать все элементы во вложенном словаре?

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

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

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

Ответ 1

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

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

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

Ответ 2

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

>>> 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 должен учитывать в этом тривиальном словаре, более интересной и продуктивной является мысль о структуре данных в первую очередь.

Основными структурами данных Python являются списки, наборы, кортежи и словари. Любая из этих структур данных может "удерживать" по ссылке любую вложенную версию себя или других структур данных.

Этот список представляет собой вложенный список:

>>> 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. Это рекурсивные структуры данных. Вы можете распечатать их с помощью 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

Ответ 3

sum(len(x) for x in food_colors.values())

Ответ 4

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

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

Ответ 5

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

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

  • считать их при построении структуры данных
  • вместо вложенных dict s, рассмотрим таблицу sqlite в памяти, используя connect(":memory:") (это может замедлить другие операции или сделать их более сложными, но компромисс стоит рассмотреть.)

Ответ 6

c = sum([len(i) for i in fruit_colors.values() ])

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

Произвольная глубина, один вкладыш:

def count(d):
    return sum([count(v) if isinstance(v, dict) else 1 for v in d.values()])