将列表中的一组URL表示为树结构

Mri*_*lla 5 python

我有一个存储URL的dicts列表.它只有两个字段,titleurl.例:

[
  {'title': 'Index Page', 'url': 'http://www.example.com/something/index.htm'}, 
  {'title': 'Other Page', 'url': 'http://www.example.com/something/other.htm'},
  {'title': 'About Page', 'url': 'http://www.example.com/thatthing/about.htm'},
  {'title': 'Detail Page', 'url': 'http://www.example.com/something/thisthing/detail.htm'},
]
Run Code Online (Sandbox Code Playgroud)

但是,我要从这个dicts列表中获取树结构.我正在寻找这样的东西:

{ 'www.example.com': 
  [ 
    { 'something': 
      [ 
        { 'thisthing':
          [
            { 'title': 'Detail Page', 'url': 'detail.htm'}
          ]
        },
        [
          { 'title': 'Index Page', 'url': 'index.htm'},
          { 'title': 'Other Page', 'url': 'other.htm'}
        ]
      ]
    },
    { 'thatthing': 
      [ 
        { 'title': 'About Page', 'url': 'about.htm'}
      ]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

我的第一次尝试是在一堆for循环中的urlparse汤,我相信有更好,更快的方法来做到这一点.

我已经看到人们在SO工作魔法上有列表推导,lambda函数等等.我仍然在搞清楚它.

(对于Django开发人员:我将使用这个我的Django应用程序.我将URL存储在一个模型中,该模型Page有两个字段,name并且title)

jro*_*jro 4

第三次是魅力所在...那是你那里有的一些很好的结构:)。在您的评论中,您提到您“无法想到更好的树格式来表示这样的数据” ......这让我再次冒昧地(稍微)改变输出的格式。为了动态添加子元素,必须创建一个字典来容纳它们。但对于“叶节点”,这个字典永远不会被填充。如果需要,这些当然可以通过另一个循环删除,但在迭代期间不会发生,因为dict应该为可能的新节点提供空。有些适用于其中没有文件的节点:这些节点将包含一个空的list.

ll = [
  {'title': 'Index Page', 'url': 'http://www.example.com/something/index.htm'}, 
  {'title': 'Other Page', 'url': 'http://www.example.com/something/other.htm'},
  {'title': 'About Page', 'url': 'http://www.example.com/thatthing/about.htm'},
  {'title': 'Detail Page', 'url': 'http://www.example.com/something/thisthing/detail.htm'},
]

# First build a list of all url segments: final item is the title/url dict
paths = []
for item in ll:
    split = item['url'].split('/')
    paths.append(split[2:-1])
    paths[-1].append({'title': item['title'], 'url': split[-1]})

# Loop over these paths, building the format as we go along
root = {}
for path in paths:
    branch = root.setdefault(path[0], [{}, []])
    for step in path[1:-1]:
        branch = branch[0].setdefault(step, [{}, []])
    branch[1].append(path[-1])

# As for the cleanup: because of the alternating lists and
# dicts it is a bit more complex, but the following works:
def walker(coll):
    if isinstance(coll, list):
        for item in coll:
            yield item
    if isinstance(coll, dict):
        for item in coll.itervalues():
            yield item

def deleter(coll):
    for data in walker(coll):
        if data == [] or data == {}:
            coll.remove(data)
        deleter(data)

deleter(root)

import pprint
pprint.pprint(root)
Run Code Online (Sandbox Code Playgroud)

输出:

{'www.example.com':
    [
        {'something':
            [
                {'thisthing':
                    [
                        [
                            {'title': 'Detail Page', 'url': 'detail.htm'}
                        ]
                    ]
                },
                [
                    {'title': 'Index Page', 'url': 'index.htm'},
                    {'title': 'Other Page', 'url': 'other.htm'}
                ]
            ],
         'thatthing':
            [
                [
                    {'title': 'About Page', 'url': 'about.htm'}
                ]
            ]
        },
    ]
}
Run Code Online (Sandbox Code Playgroud)