Элегантный алгоритм поворота словаря с использованием произвольных ключей - PullRequest
0 голосов
/ 07 мая 2020

Я ищу элегантный способ конвертировать d1 в d2. Я бы предпочел по возможности избегать «крысиного гнезда» циклов for. В идеале решение было бы читабельным и многоразовым. Я пишу на python, но было бы очень полезно решение на любом языке, не использующее специфические для языка c функции.

d1 = {
    "A": {
        "Category1": 11111,
        "Category2": 22222,
        "Category3": 33333
    },
    "B": {
        "Category1": 44444,
        "Category2": 55555,
        "Category3": 66666
    },
}

d2 = {
    "Category1": {
        "A": 111111,
        "B": 444444
    },
    "Category2": {
        "A": 222222,
        "B": 555555
    },
    "Category3": {
        "A": 333333,
        "B": 666666
    }
}

Чтобы было ясно - я не ищу для решения этой конкретной c ввода. Код довольно тривиальный (см. Ниже). Проблема с этим кодом в том, что он хрупкий и не может быть использован для решения других связанных проблем.

def pivot(d):
    data = {}
    for key, val in d.items():
        for key2, val2 in val.items():
            if key2 not in data:
                data[key2] = {}

            data[key2][key] = val2
    return data

Более сложный пример:

d1 = {
    "A": {
        "Category1": {
            "X": 111111,
            "Y": 222222,
        },
        "Category2": {
            "X": 333333,
            "Y": 444444,
        },
        "Category3": {
            "X": 555555,
            "Y": 666666,
        }
    },
    "B": {
        "Category1": {
            "X": 777777,
            "Y": 888888,
        },
        "Category2": {
            "X": 999999,
            "Y": 101010,
        },
        "Category3": {
            "X": 101011,
            "Y": 101012,
        }
    },
}

d2 = {
    "X": {
        "Category1": {
            "A": 111111,
            "B": 777777,
        },
        "Category2": {
            "A": 333333,
            "B": 999999,
        },
        "Category3": {
            "A": 555555,
            "B": 101011,
        },
    },
    "Y": {
        "Category1": {
            "A": 222222,
            "B": 888888,
        },
        "Category2": {
            "A": 444444,
            "B": 101010,
        },
        "Category3": {
            "A": 666666,
            "B": 101012,
        },
    },
}

1 Ответ

0 голосов
/ 07 мая 2020

Думаю, я нашел что-то разумное. Вот набросок кода без всех проверок крайнего случая:

def flatten_dict(d):
    if type(d) != dict:
        return [[d]]

    arr = []
    for k, v in d.items():
        for el in flatten_dict(v):
            arr.append([k] + el)

    return arr

def rearrange(in_arrs, order):
    out_arrs = []
    for arr in in_arrs:
        out_arrs += [[arr[idx] for idx in order] + [arr[-1]]]

    return out_arrs

def nest(arrays, root=None):
    if len(arrays) == 0:
        return {}


    d = root or defaultdict(dict)
    for arr in arrays:
        if len(arr) >= 2:
            head, *tail = arr
            if len(tail) == 1:
                d[head] = tail[0]
            elif len(tail) > 1:
                d[head] = nest([tail], d[head])
    return d

def pivot(d, order):
    flattened = flatten_dict(d)
    rearranged = rearrange(flattened, order)
    nested = nest(rearranged)

    return nested

d1 = {
    "A": {
        "Category1": {
            "X": 111111,
            "Y": 222222,
        },
        "Category2": {
            "X": 333333,
            "Y": 444444,
        },
        "Category3": {
            "X": 555555,
            "Y": 666666,
        }
    },
    "B": {
        "Category1": {
            "X": 777777,
            "Y": 888888,
        },
        "Category2": {
            "X": 999999,
            "Y": 101010,
        },
        "Category3": {
            "X": 101011,
            "Y": 101012,
        }
    },
}

print(pivot(d, [2, 1,0])

{
    "X": {
        "Category1": {
            "A": 111111,
            "B": 777777,
        },
        "Category2": {
            "A": 333333,
            "B": 999999,
        },
        "Category3": {
            "A": 555555,
            "B": 101011,
        },
    },
    "Y": {
        "Category1": {
            "A": 222222,
            "B": 888888,
        },
        "Category2": {
            "A": 444444,
            "B": 101010,
        },
        "Category3": {
            "A": 666666,
            "B": 101012,
        },
    },
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...