在Python中扁平化嵌套结构

2 投票
3 回答
1727 浏览
提问于 2025-04-18 08:37

我该怎么做才能把这个在Python中变得扁平化,让每个“widget”都变成列表中的一个元素呢?

{  "widgets" :[{"num": "1", "letter": "a",
              "widgets" :[{"num": "2", "letter": "b",
                           "widgets" :[{"num": "3","letter": "c"},
                                       {"num": "4", "letter": "d"}]
                         }]
            }]
}

最终结果应该是这样的

[{"num":"1", "letter","a"},
 {"num": "2", "letter":"b"},
 {"num": "3", "letter":"c"},
 {"num": "4", "letter":"d"}] 

3 个回答

0

这是我匆忙写的回复;写完后我意识到它的列表项并没有按照你指定的顺序排列;不过我觉得这可能会在递归方面给你一些启示,就像这里其他的回答一样。

注意:没有导入Python模块“elegance”。;)

def getflattenedwidgetlist(thislist):
    thislevellist = list()
    for dictionary in thislist:
        thisdict = dict()
        thislevellist.append(thisdict)
        for key in dictionary:
            if key != "widgets":
                thisdict[key] = dictionary[key]

        if "widgets" in dictionary:
            return getflattenedwidgetlist(dictionary["widgets"]) + [thisdict]

    return thislevellist


stuff = {
   "widgets" :[{
       "num": "1",
       "letter": "a",
       "widgets" :[{
         "num": "2",
         "letter": "b",
         "widgets" :[{
             "num": "3",
             "letter": "c"
           },
           { 
            "num": "4",
            "letter": "d"
           }]
        }]
    }] 
}

print getflattenedwidgetlist([stuff])
1

这里有一个递归的解决方案

def flatten_widget(widget):
    assert isinstance(widget, dict)

    # Remove any sub-level widgets for processing
    widgets = widget.pop('widgets', None)

    # The first object is itself, unless it contains nothing
    flat_list = [widget] if widget else []

    # If there are sub-level widgets, flatten them
    if widgets:
        assert isinstance(widgets, list)
        # Recursively flatten each widget and add it return list
        for w in widgets:
            flat_list += flatten_widget(w)

    # Return all widgets in a list
    return flat_list

print flatten_widget(widget)
# [{'num': '1', 'letter': 'a'}, {'num': '2', 'letter': 'b'}, {'num': '3', 'letter': 'c'}, {'num': '4', 'letter': 'd'}]

请注意,这个方法无法检测循环引用。此外,它假设你不介意原始数据结构会被修改。我没有进行性能测试,但我猜不需要复制每个字典项会稍微快一些。

4

在你处理完那些给你数据的人之后,可能会用到类似这样的代码:

def flatten_widgets(widget):
    stack = [widget['widgets']]
    while stack:
        for widget in stack.pop():
            yield {k: v for k, v in widget.items() if k != 'widgets'}
            if 'widgets' in widget:
                stack.append(widget['widgets'])

>>> list(flatten_widgets(a))

[{'letter': 'a', 'num': '1'},
 {'letter': 'b', 'num': '2'},
 {'letter': 'c', 'num': '3'},
 {'letter': 'd', 'num': '4'}]

撰写回答