Операции на подструктурах [closed]

Иногда я обнаруживаю, что делаю что-то, что изменяет только часть имеющихся у меня данных. Например:

c = {'substructure': merge(a['substructure'], b['substructure'])

Есть ли способ избежать этого повторения?

Добавим некоторые детали, это из ответ я написал на ТАК:

from itertools import groupby, chain
from collections import ChainMap

a = {
    'folders': [
        { 'id': 124, 'name': 'Leads',  'totalBlacklisted': 0, 'uniqueSubscribers': 0, 'totalSubscribers': 0 }, 
        { 'id': 123, 'name': 'Alumni', 'totalBlacklisted': 0, 'uniqueSubscribers': 0, 'totalSubscribers': 0 }, 
    ]
}

b = {
    'folders': [
        { 'id': 124, 'name': 'Leads'  },
        { 'id': 121, 'name': 'Member' },
        { 'id': 123, 'name': 'Alumni' }
    ]
}

def key(x):
    return (x['id'], x['name'])

def merge(a, b, key):
    groups = groupby(sorted(chain(a, b), key=key), key=key)
    merged = [dict(ChainMap(*g)) for _, g in groups]
    return merged

Затем применить a & b для слияния вы должны сделать это:

print({'folders': merge(a['folders'], b['folders'], key=key)})

В центре моего вопроса тот факт, что merge не нужно очищать данные.

1 ответ
1

Вопреки моему здравому смыслу, я собираюсь угадать, что вы на самом деле хотите сделать.

Сделайте нисходящий путь в вашей функции слияния, и избыточность исчезнет. В следующем примере два выхода равны:

from itertools import groupby, chain
from collections import ChainMap
from pprint import pprint
from typing import Iterable, Sequence


def merge(a, b, key):
    groups = groupby(sorted(chain(a, b), key=key), key=key)
    merged = [dict(ChainMap(*g)) for _, g in groups]
    return merged


def merge2(a: dict, b: dict, path: Iterable, keys: Sequence) -> dict:
    """
    :param a: Superior dictionary; this takes precedence
    :param b: Inferior dictionary
    :param path: The key path through both dictionaries to get to the merging dict
    :param keys: A sequence of equivalence keys upon which merging is done
    :return: The merged dictionary, contained by any wrapping dicts via path
    """

    def key_fun(inner: dict) -> tuple:
        return tuple(inner[k] for k in keys)

    # Descend to the dicts to be merged
    for p in path:
        a = a[p]
        b = b[p]

    # Merge the inner dicts
    groups = groupby(sorted(chain(a, b), key=key_fun), key=key_fun)
    merged = [dict(ChainMap(*g)) for _, g in groups]

    # Wrap the dict
    for k in reversed(path):
        merged = {k: merged}

    return merged


def main():
    def key(x):
        return x['id'], x['name']

    a = {
        'folders': [
            {'id': 124, 'name': 'Leads',  'totalBlacklisted': 0, 'uniqueSubscribers': 0, 'totalSubscribers': 0},
            {'id': 123, 'name': 'Alumni', 'totalBlacklisted': 0, 'uniqueSubscribers': 0, 'totalSubscribers': 0},
        ]
    }

    b = {
        'folders': [
            {'id': 124, 'name': 'Leads', 'totalBlacklisted': 3, 'foob': 2},
            {'id': 121, 'name': 'Member'},
            {'id': 123, 'name': 'Alumni'}
        ]
    }

    pprint({'folders': merge(a['folders'], b['folders'], key=key)})
    pprint(merge2(a, b, ('folders',), ('id', 'name')))


if __name__ == '__main__':
    main()

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *