Проблема кода - Свести словарь с помощью генератора - PullRequest
1 голос
/ 07 октября 2019

Во-первых, этот пост - решение, не использующее генераторы: Свести словарь словарей

У меня есть словарь словарей.

Например:

{
    "name": {
        "first": "One",
        "last": "Drone"
    },
    "job": "scout",
    "recent": {},
    "additional": {
        "place": {
            "zone": "1",
            "cell": "2"}
    }
}

Результат будет:

{"name/first": "One",           #one parent
 "name/last": "Drone",
 "job": "scout",                #root key
 "recent": "",                  #empty dict
 "additional/place/zone": "1",  #third level
 "additional/place/cell": "2"}

Я попытался решить его по-другому, и ключи просто не вернутся, если вы сможете мне помочьвыяснить, как использовать рекурсию там .. Кстати, это упражнение из checkio.org

def flatten(a):
    arr = flatten_dictionary(a)
    newDict = {}
    for i in arr:
        temp = i.split(':')
        try:
            newDict[temp[0]]=temp[1]
        except:
            pass
    return newDict
def flatten_dictionary(a):
    for i in a:
        if isinstance(a[i],type(dict)):
            yield from(i+'/' + flatten(a[i])) #won't enter this if scope
        else:
            yield ':'+a[i]

Вот несколько утверждений, если вы хотите проверить это ..

 assert flatten({"key": "value"}) == {"key": "value"}, "Simple"
 assert flatten(
    {"key": {"deeper": {"more": {"enough": "value"}}}}
) == {"key/deeper/more/enough": "value"}, "Nested"
assert flatten({"empty": {}}) == {"empty": ""}, "Empty value"
assert flatten({"name": {
                    "first": "One",
                    "last": "Drone"},
                "job": "scout",
                "recent": {},
                "additional": {
                    "place": {
                        "zone": "1",
                        "cell": "2"}}}
) == {"name/first": "One",
      "name/last": "Drone",
      "job": "scout",
      "recent": "",
      "additional/place/zone": "1",
      "additional/place/cell": "2"}

Кроме того, прямо сейчас это мой результат: {"":"value"}

1 Ответ

2 голосов
/ 07 октября 2019

Первая проблема заключается в том, что с if isinstance(a[i],type(dict)) вы проверяете, является ли элемент экземпляром type(dict), то есть type, а не dict, но это не решает все проблемы.

>>> type(dict)
<type 'type'>
>>> dict
<type 'dict'>

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

Вместо этого я бы предложил использовать что-то вроде этого, которое пропускает все ваши assert s:

def flatten(d):
    res = {}
    for key, val in d.items():
        if isinstance(val, dict):
            if not val:
                res[key] = ""
            for k2, v2 in flatten(val).items():
                res["%s/%s" % (key, k2)] = v2
        else:
            res[key] = val
    return res

Если вы действительно хотите сохранить этот стиль внутреннего генератора, вы можете использовать это:

def flatten(d):
    return dict(_flatten_gen(d))

def _flatten_gen(d):
    for key, val in d.items():
        if isinstance(val, dict):
            if not val:
                yield (key, "")
            yield from (("%s/%s" % (key, k2), v2) for k2, v2 in flatten(val).items())
        else:
            yield (key, val)

Обратите внимание, что это дает кортежи, которые могут быть переданы непосредственноконструктор dict вместо объединения, а затем разделения ключей и значений на :. (На самом деле, таким образом, может иметь смысл иметь генератор, так как вы можете просто вызвать _flatten_gen(d) вместо flatten(d).items(), если вы просто хотите перебрать все сплющенные элементы и не нуждаетесь в самом словаре.)

...