Разверните dict, содержащий элементы списка, в список пар dict - PullRequest
0 голосов
/ 24 июня 2018

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

data = {
  'a':0,
  'b':1,
  'c':[0, 1, 2],
  'pair':['one','two']
}

Как получить список кортежей dict в паре с pair и итерацией по c со всемиостальное остается постоянным?Например,

output = [
    ({
        'a':0,
        'b':1,
        'c':0,
        'pair':'one'
    },
    {
        'a':0,
        'b':1,
        'c':0,
        'pair':'two'
    }),
    ({
        'a':0,
        'b':1,
        'c':1,
        'pair':'one'
    },
    ...
]

Ответы [ 6 ]

0 голосов
/ 24 июня 2018

@ r3robertson , Вы также можете попробовать приведенный ниже код.Код основан на концепции list comprehension, & deepcopy() operation в Python.

Проверка Мелкая копия и глубокая копия в Python .

import pprint;
import copy;

data = {
    'a': 0,
    'b': 1,
    'c': [0, 1, 2],
    'pair': ['one','two'],
};

def get_updated_dict(data, index, pair_name):
    d = copy.deepcopy(data);
    d.update({'c': index, 'pair': pair_name});
    return d;

output = [tuple(get_updated_dict(data, index, pair_name) for pair_name in data['pair']) for index in data['c']];

# Pretty printing the output list.
pprint.pprint(output, indent=4);

Вывод "

[   (   {   'a': 0, 'b': 1, 'c': 0, 'pair': 'one'},
        {   'a': 0, 'b': 1, 'c': 0, 'pair': 'two'}),
    (   {   'a': 0, 'b': 1, 'c': 1, 'pair': 'one'},
        {   'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}),
    (   {   'a': 0, 'b': 1, 'c': 2, 'pair': 'one'},
        {   'a': 0, 'b': 1, 'c': 2, 'pair': 'two'})]

Хорошая печать с использованием jsonмодуль "

Примечание: Кортеж здесь преобразуется в список, поскольку кортежи не поддерживаются внутри JSON.

import json;
print(json.dumps(output, indent=4));

Вывод"

[
    [
        {
            "a": 0,
            "c": 0,
            "b": 1,
            "pair": "one"
        },
        {
            "a": 0,
            "c": 0,
            "b": 1,
            "pair": "two"
        }
    ],
    [
        {
            "a": 0,
            "c": 1,
            "b": 1,
            "pair": "one"
        },
        {
            "a": 0,
            "c": 1,
            "b": 1,
            "pair": "two"
        }
    ],
    [
        {
            "a": 0,
            "c": 2,
            "b": 1,
            "pair": "one"
        },
        {
            "a": 0,
            "c": 2,
            "b": 1,
            "pair": "two"
        }
    ]
]
0 голосов
/ 24 июня 2018

Не слишком идеально, но вот мое решение.

data = { 'a':0, 'b':1, 'c':[0, 1, 2], 'pair':['one','two'] }
a,b = data['pair'], data['c']
for t in range(0, len(b)):
  for u in range(0, len(a)):
    for h in a:
        data['c']=b[t]
        data['pair']=a[u]
    print(tuple([data]))
0 голосов
/ 24 июня 2018

Это довольно расширенное решение:

data = {
  'a':0,
  'b':1,
  'c':[0, 1, 2],
  'pair':['one','two']
}

# Get the length of the longest sequence
length = max(map(lambda x: len(x) if isinstance(x, list) else 1, data.values()))

# Loop through the data and change scalars to sequences
# while also making sure that smaller sequences are stretched to match
# or exceed the length of the longest sequence
for k, v in data.items():
    if isinstance(v, list):
        data[k] = v * int(round(length/len(v), 0))
    else:
        data[k] = [v] * length

# Create a dictionary to keep track of which outputs
# need to end up in which tuple
seen = dict.fromkeys(data.get('pair'), 0)
output = [tuple()] * len(seen)

# Loop through the data and place dictionaries in their
# corresponding tuples.
for v in zip(*data.values()):
        d = dict(zip(data, v))
        output[seen[d.get('pair')]] += (d,)
        seen[d.get('pair')] += 1

print(output)

Идея состоит в том, чтобы преобразовать скаляры в ваших данных в последовательности, длина которых соответствует длине самой длинной последовательности в исходных данных. Поэтому первым делом я присвоил переменной length размер самой длинной последовательности. Вооружившись этим знанием, мы перебираем исходные данные и расширяем уже существующие последовательности, чтобы соответствовать размеру самой длинной последовательности, преобразовывая скаляры в последовательности. Как только это будет сделано, мы переходим к генерации переменной output. Но сначала мы создаем словарь с именем seen, который поможет нам создать список кортежей и отследить, какая группа словарей в каком кортере заканчивается. Это позволяет нам выполнить один последний цикл, чтобы поместить группы словарей в соответствующие им кортежи.

Токовый выход выглядит следующим образом:

[({'a': 0, 'b': 1, 'c': 0, 'pair': 'one'},
  {'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}),
 ({'a': 0, 'b': 1, 'c': 2, 'pair': 'one'},)]

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

0 голосов
/ 24 июня 2018

Вы можете использовать itertools:

import itertools
data = {
  'a':0,
  'b':1,
  'c':[0, 1, 2],
  'pair':['one','two']
}
def expand_dict(data):
   grouped = [a for a, b in data.items() if isinstance(b, list)]
   p = [[a, list(b)] for a, b in itertools.groupby(itertools.product(*[data[i] for i in grouped]), key=lambda x:x[0])]
   return [tuple({**data, **dict(zip(grouped, i))} for i in c) for _, c in p]

print(expand_dict(data))

Выход:

[({'a': 0, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 0, 'pair': 'two'}), 
 ({'a': 0, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}), 
 ({'a': 0, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 2, 'pair': 'two'})]

Это решение также будет работать на вводе со многими возможными списками значений:

data = {'a':[5, 6, 1, 3], 'b':1, 'c':[0, 1, 2], 'pair':['one', 'two']}
print(expand_dict(data))

Вывод:

[({'a': 5, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 5, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 5, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 5, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 5, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 5, 'b': 1, 'c': 2, 'pair': 'two'}), ({'a': 6, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 6, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 6, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 6, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 6, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 6, 'b': 1, 'c': 2, 'pair': 'two'}), ({'a': 1, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 1, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 1, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 1, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 1, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 1, 'b': 1, 'c': 2, 'pair': 'two'}), ({'a': 3, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 3, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 3, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 3, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 3, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 3, 'b': 1, 'c': 2, 'pair': 'two'})]
0 голосов
/ 24 июня 2018

Вы можете использовать itertools.product для значений списка и отслеживать ключ, с которого произошел каждый элемент. Поскольку ключ 'pair' имеет особое значение, вам следует обращаться с ним отдельно.

код

from itertools import product

def unzip_dict(d):
    keys = [k for k, v in d.items() if isinstance(v, list) and k != 'pair']
    values = [d[k] for k in keys]

    for values in product(*values):
        yield tuple({**d, **dict(zip(keys, values)), 'pair': pair} for pair in d['pair'])

Пример

data = {
    'a': 0,
    'c': [1, 2],
    'pair': ['one', 'two']
}

print(*unzip_dict(data))

выход

({'a': 0, 'c': 1, 'pair': 'one'}, {'a': 0, 'c': 1, 'pair': 'two'})
({'a': 0, 'c': 2, 'pair': 'one'}, {'a': 0, 'c': 2, 'pair': 'two'})
0 голосов
/ 24 июня 2018

Что ж, это не выглядит особенно элегантно, но вы можете использовать вложенные для цикла или понимания списка:

output = []
for i in data['c']:
  output.append(tuple({'a': 0, 'b': 1, 'c': i, 'pair': p} for p in data))

или

output = [tuple({'a': 0, 'b': 1, 'c': i, 'pair': p} for p in data['pair']) for i in data['c']]

Более чистое решение может отделитьгенерация компонента вписывается в функцию, например:

def gen_output_dict(c, pair):
  return {'a': 0, 'b': 1, 'c': c, 'pair': pair}

output = []
for i in data['c']:
  output.append(tuple(gen_output_dict(i, p) for p in data['pair']))
...