Как сгладить только второй уровень списка списков (чтобы позже превратить его в словарь) в python?

У меня есть список списков, которые я позже хочу превратить в словарь. Проблема в том, что список списков очень нерегулярен: для одного ключа существует от 1 до 4 списков с номерами, принадлежащими этому ключу. Исходный набор данных хранится в json. Это примерный набор данных:

data = [36146779,
[17628,35633, 2847385, 71393, 41814],[51068348,49722,3255134,66598],[103475099, 1337536, 1136863360,257],
22971125,
[230806,116805,118456,9031, 3573662],[719279707,299836,40722,35134,668],[1337536, 1136863360,257],
111125168,
[719279707,299836,40722,35138],[17628,35633, 2847385],
71280747,
[806,116805,11845],[17628,35633, 2847385]]

Мне удалось полностью сгладить список списков, но я застрял, превращая этот плоский список в словарь с заданными ключами.

ex_eco = ["36146779","22971125","111125168","71280747"]

(Я уверен, что также можно напрямую превратить первый вложенный список в словарь, но я не смог найти решение, поэтому попробовал так)

def flatten(l):
  out = []
  for item in l:
    if isinstance(item, (list, tuple)):
      out.extend(flatten(item))
    else:
      out.append(item)
  return out

flattened_eco = flatten(data)

print(flattened_eco[0:100])

Я получаю плоский список:

[36146779, 17628, 35633, 2847385, 71393, 41814, 51068348, 49722, 3255134, 66598, 103475099, 1337536, 1136863360, 257, 22971125, 230806, 116805, 118456, 9031, 3573662, 719279707, 299836, 40722, 35134, 668, 1337536, 1136863360, 257, 111125168, 719279707, 299836, 40722, 35138, 17628, 35633, 2847385, 71280747, 806, 116805, 11845, 17628, 35633, 2847385]

Мне нужно что-то вроде этого:

[36146779,
[17628,35633, 2847385, 71393,41814,51068348,49722,3255134,66598,103475099,1337536, 1136863360,257],
22971125,
[230806,116805,118456,9031,573662,719279707,299836,40722,35134,668,1337536, 1136863360,257],
111125168,
[719279707,299836,40722,35138,17628,35633, 2847385],
71280747,
[806,116805,11845,17628,35633, 2847385]
]

person Theresa S    schedule 22.07.2019    source источник
comment
Каков ваш желаемый результат?   -  person AdamGold    schedule 22.07.2019
comment
Привет, AdamGold, мне нужен список с будущими ключами и будущими значениями, например. [36146779, [5,6,7,8], 434,[6,4,5,6], 57647[34,23,78,45]]. Пожалуйста, смотрите последний раздел моего вопроса для лучшего описания.   -  person Theresa S    schedule 22.07.2019
comment
Кори, да, ты прав. Я исправил это, спасибо!   -  person Theresa S    schedule 22.07.2019


Ответы (4)


import itertools

def flatten(data):
    flattened = []
    for key, value in itertools.groupby(data, type):
        if key == int:
            flattened.append(next(value))
        else:
            flattened.append(list(itertools.chain.from_iterable(value)))
    return flattened

Пример

>>> data = [36146779,
            [17628,35633, 2847385, 71393, 41814],[51068348,49722,3255134,66598],[103475099, 1337536, 1136863360,257],
            22971125,
            [230806,116805,118456,9031, 3573662],[719279707,299836,40722,35134,668],[1337536, 1136863360,257],
            111125168,
            [719279707,299836,40722,35138],[17628,35633, 2847385],
            71280747,
            [806,116805,11845],[17628,35633, 2847385]]

>>> flatten(data)
[36146779, 
 [17628, 35633, 2847385, 71393, 41814, 51068348, 49722, 3255134, 66598, 103475099, 1337536, 1136863360, 257],
 22971125,
 [230806, 116805, 118456, 9031, 3573662, 719279707, 299836, 40722, 35134, 668, 1337536, 1136863360, 257],
 111125168,
 [719279707, 299836, 40722, 35138, 17628, 35633, 2847385],
 71280747,
 [806, 116805, 11845, 17628, 35633, 2847385]]

Чтобы сделать еще один шаг и создать словарь, просто измените последнюю строку функции на dict понимание

def dictify(data):
    flattened = []
    for key, value in itertools.groupby(data, type):
        if key == int:
            flattened.append(next(value))
        else:
            flattened.append(list(itertools.chain.from_iterable(value)))
    return {key:value for key,value in zip(flattened[::2], flattened[1::2])}

>>> dictify(data)
{36146779: [17628, 35633, 2847385, 71393, 41814, 51068348, 49722, 3255134, 66598, 103475099, 1337536, 1136863360, 257],
 22971125: [230806, 116805, 118456, 9031, 3573662, 719279707, 299836, 40722, 35134, 668, 1337536, 1136863360, 257],
 111125168: [719279707, 299836, 40722, 35138, 17628, 35633, 2847385],
 71280747: [806, 116805, 11845, 17628, 35633, 2847385]}
person Cory Kramer    schedule 22.07.2019
comment
Это именно то, что я искал - Спасибо! Я обязательно посмотрю на пакет itertools. Не могли бы вы объяснить эту if key == int: логику? - person Theresa S; 22.07.2019
comment
Функция, которую я передал groupby, была type. Поэтому, когда вы перебираете группы, вы получите пары (key, group). Поскольку я группирую по type, я хочу обрабатывать отдельные значения int иначе, чем значения list, которые я хочу позже сгладить. - person Cory Kramer; 22.07.2019

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

result = {}
keys = []
for d in data:
  if type(d) == int:
    result[d] = []
    keys.append(d)
  else:
    result[keys[-1]] += d

Вывод с использованием предоставленных данных:

{36146779: [17628, 35633, 2847385, 71393, 41814, 51068348, 49722, 3255134, 66598, 103475099, 1337536, 1136863360, 257], 22971125: [230806, 116805, 118456, 9031, 3573662, 719279707, 299836, 40722, 35134, 668, 1337536, 1136863360, 257], 111125168: [719279707, 299836, 40722, 35138, 17628, 35633, 2847385], 71280747: [806, 116805, 11845, 17628, 35633, 2847385]}
person Vanojx1    schedule 22.07.2019

  • extend() — используется для объединения двух списков.

Напр.

data = [36146779,
[17628,35633, 2847385, 71393, 41814],[51068348,49722,3255134,66598],[103475099, 1337536, 1136863360,257],
22971125,
[230806,116805,118456,9031, 3573662],[719279707,299836,40722,35134,668],[1337536, 1136863360,257],
111125168,
[719279707,299836,40722,35138],[17628,35633, 2847385],
71280747,
[806,116805,11845],[17628,35633, 2847385]]

new_dict = {}
temp=None
for x in data:
    if not isinstance(x, list):
        new_dict[x] = []
        temp = x
    else:
        new_dict[temp].extend(x)

print(new_dict)

О/П:

{36146779: [17628, 35633, 2847385, 71393, 41814, 51068348, 49722, 3255134, 66598, 103475099, 1337536, 1136863360, 257], 22971125: [230806, 116805, 118456, 9031, 3573662, 719279707, 299836, 40722, 35134, 668, 1337536, 1136863360, 257], 111125168: [719279707, 299836, 40722, 35138, 17628, 35633, 2847385], 71280747: [806, 116805, 11845, 17628, 35633, 2847385]}
person bharatk    schedule 22.07.2019
comment
Спасибо bharatk, этот код тоже работает. просто в учебных целях: что делает Temp=none? - person Theresa S; 22.07.2019
comment
@TheresaS Инициализировать значение None в переменной temp, далее мы используем temp variable как dictionary key. - person bharatk; 23.07.2019

Одна версия с использованием itertools.groupby:

data = [36146779,
[17628,35633, 2847385, 71393, 41814],[51068348,49722,3255134,66598],[103475099, 1337536, 1136863360,257],
22971125,
[230806,116805,118456,9031, 3573662],[719279707,299836,40722,35134,668],[1337536, 1136863360,257],
111125168,
[719279707,299836,40722,35138],[17628,35633, 2847385],
71280747,
[806,116805,11845],[17628,35633, 2847385]]

from itertools import groupby

def generate(d):
    for v, g in groupby(d, lambda k: isinstance(k, (tuple, list))):
        if not v:
            yield from g
        else:
            yield sum(g, [])

from pprint import pprint
pprint([*generate(data)], width=180)

Отпечатки:

[36146779,
 [17628, 35633, 2847385, 71393, 41814, 51068348, 49722, 3255134, 66598, 103475099, 1337536, 1136863360, 257],
 22971125,
 [230806, 116805, 118456, 9031, 3573662, 719279707, 299836, 40722, 35134, 668, 1337536, 1136863360, 257],
 111125168,
 [719279707, 299836, 40722, 35138, 17628, 35633, 2847385],
 71280747,
 [806, 116805, 11845, 17628, 35633, 2847385]]
person Andrej Kesely    schedule 22.07.2019