在Python中遍历涉及嵌套列表和嵌套字典的数据结构。

5
我正在尝试遍历这种树形结构,想要获取所有的“标题”。请注意,这个结构可能会越来越大,也就是说每个标题在将来可能会有更多的子类别。有什么想法吗?
我正在尝试做到以下几点:

def continue_searching(item):
    for i in len(item):
        if categories[i]["subcategories"]:
            continue_searching(i["subcategories"])
            print(i["subcategories"])


def give_titles(categories):
    for i in len(categories):
        if categories[i]["subcategories"]:
            continue_searching(i["subcategories"])
        print(i['title'])


categories = [
    {
        "title": "Food",
        "subcategories": [
            {"title": "Bread"},
            {
                "title": "Meat",
                "subcategories": [
                    {"title": "Pork",
                     "subcategories": [
                         {"title": "White Pork"},
                         {"title": "Red Pork"}
                     ]
                     },
                    {"title": "Beef"},
                ],
            },
            {"title": "Cheese"},
        ],
    },
    {"title": "Drinks"},
]

give_titles(categories)


期望输出:

Food
-Bread
-Meat
--Pork
---White Pork
---Red Pork
--Beef
-Cheese
Drinks

请注意,我没有使用递归,因为我不清楚何时停止调用,并且我不想使调用栈饱和。

1
我不明白这个输出。为什么有3个“Porks”?通过获取标题,您想把它们放到字典中吗?还是列表?它们已经在数据结构中了。 - Bharel
因为有三个键名为"title"且值为"pork"。 - Nicolas
我认为你在猪肉条目中多了一些换行符。我的更正看起来正确吗? - John Kugelman
你想要打印输出吗?你遍历的目标是什么?@JohnKugelman的更正是你想要打印的实际输出吗? - Bharel
@Nicolas 更新了非递归答案。 - Bharel
显示剩余2条评论
5个回答

2

定义这个函数:

def write_titles(cats, depth=0):
  for c in cats:
    print('-'*depth, c['title'])
    write_titles(c.get('subcategories', []), depth+1)

然后使用 write_titles(categories) 调用它。

1
遍历和打印像这样的数据结构通常使用递归来完成,就像你尝试的那样。
在你的代码中,我们希望在数据结构的每个进一步嵌套上重复调用一个函数。
示例代码:
def print_titles(categories, depth=0):
    for category in categories:
        print('-' * depth, category['title'])
        if 'subcategories' in category:
            print_titles(category['subcategories'], depth + 1)

如果您更改了问题并希望得到一个不需要递归的解决方案,最好的方法可能是使用迭代器,如下所示:

def print_titles(categories):
    stack = [iter(categories)]
    while stack:
        iterator = stack.pop()
        for item in iterator:
            print("-" * len(stack), item['title'])
            if 'subcategories' in item:
                stack.append(iterator)
                stack.append(iter(item['subcategories']))
                break

1
您可以使用递归编程。
def get_all_titles(data, output=[]):
    if isinstance(data, dict):
            output.append(data.get("title"))
            data = data.get("subcategories", [])
    if isinstance(data, list):
            for item in data:
                    get_all_titles(item)
    return output

输出

print(get_all_titles(categories))
['Food', 'Bread', 'Meat', 'Pork', 'White Pork', 'Red Pork', 'Beef', 'Cheese', 'Drinks']

1
您定义的结构本质上是一个单独树的列表。
我只是遍历了列表中的每个“子树”,并对每个子树进行了先序遍历。
categories = [
{
    "title":         "Food",
    "subcategories": [
        {"title": "Bread"},
        {
            "title": "Meat",
            "subcategories": [
            {"title": "Pork",
                "subcategories": [
                {"title": "White Pork"},
                {"title": "Red Pork"}
                ]
            },
            {"title": "Beef"},
            ],
        },
        {"title": "Cheese"},
        ],
},
{"title": "Drinks"},
]


# What's really defined here is like a list of trees

def preorder(root, depth):
    print("-" * depth + root["title"])
    if "subcategories" in root:
        for child in root["subcategories"]:
            preorder(child, depth + 1)


def printCategories(categories):
    for tree in categories:
        preorder(tree, 0)
    
printCategories(categories)

这将输出:

Food
-Bread
-Meat
--Pork
---White Pork
---Red Pork
--Beef
-Cheese
Drinks

既然你提到你不想使用递归,那么就像这里所示,使用自己的堆栈来执行遍历操作。


1
def all_titles(data, output=[]):

    if x(data, dict):
            output.append(data.get("title"))
            data = data.get("subcategories", [])
    
    if x(data, list):
            for y in data:
                    all_titles(item)
    return

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接