построение словарей из списка на основе повторяющегося элемента - PullRequest
0 голосов
/ 21 июня 2020

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

В настоящее время я пытаюсь решить эту проблему с помощью серии циклов for и Я думаю, что это, вероятно, простое перечисление + zip где-то.

items = [
    {
        "0": 'name',
        "1": 'phone',
        "2": 'email'
    },
    {
        "0": "John",
        "1": "8888888888",
        "2": "email@email.com"
    },
    {
        "0": "James",
        "1": "7777777777",
        "2": "email@email.com"
    },
    {
        "0": 'name',
        "1": 'phone',
        "2": 'email'
    },
    {
        "0": "Jim",
        "1": "8888888888",
        "2": "email@email.com"
    },
    {
        "0": "Joe",
        "1": "7777777777",
        "2": "email@email.com"
    },
]

Обратите внимание, что элементы 0 и 3 являются «заголовками» и одинаковы. Мне нужно сгруппировать контакты в новый объект. Группы состоят из данных между каждым заголовком. это будет выглядеть так:

new_items = [
    {
        "group_one": [
            {
                "0": 'name',
                "1": 'phone',
                "2": 'email'
            },
            {
                "0": "John",
                "1": "8888888888",
                "2": "email@email.com"
            },
            {
                "0": "James",
                "1": "7777777777",
                "2": "email@email.com"
            },
        ] 
    },
    {
        "group_two": [
            {
                "0": 'name',
                "1": 'phone',
                "2": 'email'
            },
            {
                "0": "Jim",
                "1": "8888888888",
                "2": "email@email.com"
            },
            {
                "0": "Joe",
                "1": "7777777777",
                "2": "email@email.com"
            },
        ]
    }
]

Затем каждый элемент после заголовка в этих новых списках необходимо объединить. Что-то вроде:

combined_items = [
    {
        "group_one":
            {
                'name': 'John/James',
                'phone': '8888888888/7777777777',
                'email': 'email@email.com/email@email.com'
            }
    },
    {
        "group_two":
            {
                'name': 'Jim/Joe',
                'phone': '8888888888/7777777777',
                'email': 'email@email.com/email@email.com'
            }
    }
]

Сейчас я делаю это:


cleaned_dictionaries = []

for row in items:
   if isinstance(row, dict):
      if row.get('0', None) != 'name':
         cleaned_dictionaries.append(row)

header_values = items[0].values()

rows = [dict(zip(header_values, d.values())) for d in cleaned_dictionaries]

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

Проблема в том, что я не могу объединить свои группы.

Ответы [ 2 ]

3 голосов
/ 21 июня 2020

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

from itertools import groupby
from pprint import pprint

headers = {"0": "name", "1": "phone", "2": "email"}

groups = [list(g) for k, g in groupby(items, key=lambda item: item == headers) if not k]

pprint(groups)

Что даст вам следующие группировки:

[[{'0': 'John', '1': '8888888888', '2': 'email@email.com'},
  {'0': 'James', '1': '7777777777', '2': 'email@email.com'}],
 [{'0': 'Jim', '1': '8888888888', '2': 'email@email.com'},
  {'0': 'Joe', '1': '7777777777', '2': 'email@email.com'}]]

Затем вы можете перебирать эти группы, использовать collections.defaultdict для группировки каждого словаря по заголовкам, а затем добавить окончательный результат в объединенный словарь:

from collections import defaultdict

combined_items = {}
for idx, group in enumerate(groups, start=1):
    header_groups = defaultdict(list)

    for dic in group:
        for k, v in dic.items():
            header_groups[headers[k]].append(v)

    combined_items[f"group_{idx}"] = {k: "/".join(v) for k, v in header_groups.items()}

pprint(combined_items, sort_dicts=False)

Что дает:

{'group_1': {'name': 'John/James',
             'phone': '8888888888/7777777777',
             'email': 'email@email.com/email@email.com'},
 'group_2': {'name': 'Jim/Joe',
             'phone': '8888888888/7777777777',
             'email': 'email@email.com/email@email.com'}}
2 голосов
/ 21 июня 2020

С такими данными вам будет гораздо лучше использовать pandas:

In [15]: import pandas as pd

In [16]: df = pd.DataFrame(items)

In [17]: df.groupby(df['0'].eq('name').cumsum()).agg(lambda x: '/'.join(x[1:])).rename(columns={'0': 'name', '1': 'phone', '2': 'email'})

Out[17]:
         name                  phone                            email
0
1  John/James  8888888888/7777777777  email@email.com/email@email.com
2     Jim/Joe  8888888888/7777777777  email@email.com/email@email.com
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...