Как быстро разбить словарь на несколько словарей

Я нашел решение, но он очень медленный:

def chunks(self,data, SIZE=10000):
    for i in xrange(0, len(data), SIZE):
        yield dict(data.items()[i:i+SIZE])

Есть ли у вас идеи без использования внешних модулей (numpy и т.д.).

Ответ 1

Поскольку словарь настолько велик, было бы лучше, чтобы все элементы были просто итераторами и генераторами, такими как

from itertools import islice

def chunks(data, SIZE=10000):
    it = iter(data)
    for i in xrange(0, len(data), SIZE):
        yield {k:data[k] for k in islice(it, SIZE)}

Пример прогона:

for item in chunks({i:i for i in xrange(10)}, 3):
    print item

Выход

{0: 0, 1: 1, 2: 2}
{3: 3, 4: 4, 5: 5}
{8: 8, 6: 6, 7: 7}
{9: 9}

Ответ 2

Другой метод - итераторы zipping:

>>> from itertools import izip_longest, ifilter
>>> d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':6, 'g':7, 'h':8}

Создайте список с копиями диктовых итераторов (количество копий - это количество элементов в результатах dicts). Передавая каждый итератор из chunks списка izip_longest, вы получите необходимое количество элементов из источника dict (ifilter используется для удаления None из результатов zip). С выражением генератора вы можете уменьшить использование памяти:

>>> chunks = [d.iteritems()]*3
>>> g = (dict(ifilter(None, v)) for v in izip_longest(*chunks))
>>> list(g)
[{'a': 1, 'c': 3, 'b': 2},
 {'e': 5, 'd': 4, 'g': 7},
 {'h': 8, 'f': 6}]

Ответ 3

Решение Python3, основанное на подходе @ndpu:

from itertools import zip_longest
chunks = [self.data_to_process.items()] * self.no_of_processes
g = (dict(filter(None, v)) for v in zip_longest(*chunks))
chunked_data = list(g)

Узлы:

  1. itertools.ifilter() был удален в Python 3, потому что встроенная функция filter() теперь предоставляет те же функции. Источник

  2. Поскольку вы находитесь в python3, используйте dict.items() вместо dict.iteritems() Source

  3. izip_longest был переименован в zip_longest в Python 3 Source

Ответ 4

Этот код берет большой словарь и разбивает его на список небольших словарей. Переменная max_limit указывает максимальное количество пар ключ-значение, разрешенных в под-словаре. Этот код не требует особых усилий, чтобы разбить словарь, только один полный анализ словарного объекта.

import copy
def split_dict_to_multiple(input_dict, max_limit=200):
"""Splits dict into multiple dicts with given maximum size. 
Returns a list of dictionaries."""
chunks = []
curr_dict ={}
for k, v in input_dict.items():
    if len(curr_dict.keys()) < max_limit:
        curr_dict.update({k: v})
    else:
        chunks.append(copy.deepcopy(curr_dict))
        curr_dict = {k: v}
# update last curr_dict
chunks.append(curr_dict)
return chunks

Ответ 5

import numpy as np
chunk_size = 3
chunked_data = [[k, v] for k, v in d.items()]
chunked_data = np.array_split(chunked_data, chunk_size)

После этого у вас есть ndarray который можно повторять так:

for chunk in chunked_data:
    for key, value in chunk:
        print(key)
        print(value)

Который может быть переназначен списку диктов с помощью простого цикла for.