Как найти минимальное значение многомерного диктата? - PullRequest
2 голосов
/ 15 апреля 2020

У меня есть подобный dict, и я хочу найти минимальное значение:

fault = {
        'A': {
            'X': {
                10: 0.34,
                12: 0.32,
                15: 1.53,
                ...
                43: 0.2314
            },
            'Y': {
                10: 0.12,     <--- Min
                12: 0.32,
                15: 0.3214,
                ...
                43: 1.4
            }
        },
        'B': {
            'X': {...},
            'Y': {...}
        },
        'C': {
            'X': {...},
            'Y': {...}
        },
        'D': {
            'A': {...},
            'T': {...}
        },
        ...
        'Z': {...}
    }

Как найти минимальное значение внутреннего dict с ключами? Ожидаемый результат выглядит примерно так:

('A', ('Y', {10: 0.12}))

или

['A', 'Y', 10, 0.12]

Неважно, какой тип данных выводится, пока он дает желаемый

Примечание: вложенные дикторы имеют одинаковую длину

Ответы [ 6 ]

2 голосов
/ 15 апреля 2020

Вы можете использовать генераторное выражение со встроенной функцией min:

min(((i, (k0, (k1, {k2: i}) )) 
    for k0, d in fault.items()
    for k1, v in d.items()
    for k2, i in v.items()), key=lambda x: x[0])[1]

выход:

('A', ('Y', {10: 0.12}))

если у вас есть

2 голосов
/ 15 апреля 2020

Вы можете использовать рекурсию:

def d_min(d, c = []):
   if all(not isinstance(i, dict) for i in d.values()):
     _m = min(d.values())
     yield (c, {a:b for a, b in d.items() if b == _m}, _m)
   else:
     yield from [i for a, b in d.items() for i in d_min(b, c+[a])]

def to_tuple(d, v):
  return (d[0], v if not d[1:] else to_tuple(d[1:], v))

p, result, _ = min(d_min(fault), key=lambda x:x[-1])
print(to_tuple(p, result))

Вывод:

('A', ('Y', {10: 0.12}))
1 голос
/ 15 апреля 2020

Вы можете использовать выражение генератора, которое проходит через 3 уровня структуры dict и выводит самые внутренние элементы в ожидаемом формате, и передает его в функцию min с помощью ключевой функции, которая возвращает значение самого внутреннего dict :

min(((k, (s, {i: v})) for k, d in fault.items() for s, m in d.items()
    for i, v in m.items()), key=lambda t: next(iter(t[1][1].values())))
1 голос
/ 15 апреля 2020

Вам придется сгладить структуру словаря, сохранив иерархию ключей, соответствующую каждому значению. Затем используйте функцию min в выровненном списке и на основе этого создайте свой вложенный результат tuple / dict.

K1,K2,K3,V3 = min( (K1,K2,K3,V3) for K1,V1 in fault.items() for K2,V2 in V1 for K3,V3 in V2),key=lambda r:r[-1])

result = (K1,(K2,{K3:V3}))

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

def flatDict(D):
    for K,V in D.items():
        if isinstance(V,dict):
            for KVn in flatDict(V):
                yield (K,)+KVn
        else:
            yield (K,V)

*keys,lastKey,value = min(flatDict(fault),key=lambda r:r[-1])

result = {lastKey:value}
for key in reversed(keys):
    result = (key,result)

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

0 голосов
/ 15 апреля 2020

Общее рекурсивное решение:

array = {
    'A': {
        'X': {
            10: 0.34,
            12: 0.32,
            15: 1.53,
            43: 0.2314,
        },
        'Y': {
            10: 0.12,
            12: 0.32,
            15: 0.3214,
            43: 1.4
        }
    },
}

def find_min(elem):
    current_min = None
    if isinstance(elem, dict):
        for key, values in elem.items():
            m = find_min(values)
            if not current_min or m < current_min:
                current_min = m
    elif isinstance(elem, list):
        for e in elem:
            m = find_min(values)
            if not current_min or m < current_min:
                current_min = m
    else:
        current_min = elem
    return current_min


print(find_min(array))
0 голосов
/ 15 апреля 2020

Вы можете вложить функцию min с помощью итераторов списка:

min([min([min(dd.values()) for dd in d.values()]) for d in fault.values()])

Не является общим решением для произвольных глубин.

...