如何在Python中将列表转换为嵌套dict

如何在Python中将列表转换为嵌套dict,python,list,dictionary,nested,Python,List,Dictionary,Nested,需要转x: X = [['A', 'B', 'C'], ['A', 'B', 'D']] 进入Y: Y = {'A': {'B': {'C','D'}}} 更具体地说,我需要从绝对路径列表创建文件夹和文件树,如下所示: paths = ['xyz/123/file.txt', 'abc/456/otherfile.txt'] 其中,根据伪示例中的['A',B',C'],每个路径都被拆分(“/”) 由于这表示文件和文件夹,显然,在同一级别(数组的索引)上,相同名称的字符串不能重复 您的问题陈

需要转x:

X = [['A', 'B', 'C'], ['A', 'B', 'D']]
进入Y:

Y = {'A': {'B': {'C','D'}}}
更具体地说,我需要从绝对路径列表创建文件夹和文件树,如下所示:

paths = ['xyz/123/file.txt', 'abc/456/otherfile.txt']
其中,根据伪示例中的
['A',B',C']
,每个路径都被拆分(“/”)


由于这表示文件和文件夹,显然,在同一级别(数组的索引)上,相同名称的字符串不能重复

您的问题陈述在逻辑上不一致。如果你真的想
['xyz/123/file.txt','abc/456/otherfile.txt']

改为
{'xyz':{'123':'file.txt},'abc':{'456':'otherfile.txt'}


然后,您必须回答如何将没有前导文件夹的路径“abc.txt”插入到该数据结构中。顶层字典键是空字符串吗?

假设
{C',D'}
表示
集合(['C',D'])
并且您的Python版本支持
dict comprehension
集合comprehension
,下面是一个丑陋但有效的解决方案:

>>> tr = [[1, 2, 3], [1, 2, 4], [5, 6, 7]]
>>> {a[0]: {b[1]: {c[2] for c in [y for y in tr if y[1] == b[1]]} for b in [x for x in tr if x[0] == a[0]]} for a in tr}
{1: {2: set([3, 4])}, 5: {6: set([7])}}
至于你的例子:

>>> X = [['A', 'B', 'C'], ['A', 'B', 'D']]
>>> {a[0]: {b[1]: {c[2] for c in [y for y in X if y[1] == b[1]]} for b in [x for x in X if x[0] == a[0]]} for a in X}
{'A': {'B': set(['C', 'D'])}}
但请不要在实际应用程序中使用它:)

更新:这里有一个适用于任意深度的:

>>> def todict(lst, d=0):
...     print lst, d
...     if d > len(lst):
...         return {}
...     return {a[d]: todict([x for x in X if x[d] == a[d]], d+1) for a in lst}
...
>>> todict(X)
{'A': {'B': {'C': {}, 'D': {}}}}

这应该非常接近您所需要的:

def path_to_dict(path):
    parts = path.split('/')

    def pack(parts):
        if len(parts) == 1:
            return parts
        elif len(parts):
            return {parts[0]: pack(parts[1:])}
        return parts

    return pack(parts)

if __name__ == '__main__':
    paths = ['xyz/123/file.txt', 'abc/456/otherfile.txt']
    for path in paths:
        print '%s -> %s' % (path, path_to_dict(path))
结果:

xyz/123/file.txt -> {'xyz': {'123': ['file.txt']}}
abc/456/otherfile.txt -> {'abc': {'456': ['otherfile.txt']}}

这就留下了包含
{'A':{'B':{'C':{},'d':{}},'W':{'Y':{'Z':{},'X':{}
。任何包含空字典的条目都是一个文件或一个空目录。

我在twitter上被问及这个问题,并使用函数式编程提出了这个巧妙的解决方案,我想我不妨在这里分享一下

from functools import reduce
X = [['A', 'B', 'C'], ['A', 'B', 'D']]
Y = [reduce(lambda x, y: {y:x}, Y[::-1]) for Y in X]
返回:

[{'A': {'B': 'C'}}, {'A': {'B': 'D'}}]
{'A': {'B': 'C'}}
如所愿

对于一个更简单的问题,如果您有一个列表要用嵌套键表示为dict,那么这就足够了:

from functools import reduce
X = ['A', 'B', 'C']
reduce(lambda x, y: {y:x}, X[::-1])
返回:

[{'A': {'B': 'C'}}, {'A': {'B': 'D'}}]
{'A': {'B': 'C'}}

这是什么
{'C','D'}
您试图用嵌套的dict解决什么问题?如果文件夹A包含目录B和文件X怎么办?该如何表示?这是否可以接受<代码>{'A':{'B':{'C':{},'D':{}}}更一致的是,Y={'A':{'B':{'C':{},'D':{}}也不适用于任意深度,这可能是一个要求。@true-我认为这不是一个要求,但可能是。我是否应该想出一个更可怕的单行侠?:)哈,那就太可怕了。我认为Matt有这个想法——它必须递归地完成。你如何加入所有的字典,比如如果你有其他路径,如
xyz/123/b.a
abc/sss/ooo/1.a
与这些路径重叠?如果
'xyz'
包含目录和文件呢?Matt,我正要问与agf相同的问题。到目前为止,我自己做到了。我真的需要一本字典。会有重叠,所以我不能完全替换节点,实际上需要在每一层进行合并。深度合并指令:如果在顶层有一个名为abc.txt的文件,它将是一个带有“xyz”和“abc”的对等文件,如{'xyz':{…},'abc':{…},'abc.txt:{}。对于空的{},表示它是一个叶子,如果某个东西“看起来”像文件或文件夹,则无关紧要。最后一个是文件,其余是文件夹。顺便说一句,这不是真正的文件系统。当前的_级别在哪里添加到d?@Tyler Hilbert当前的_级别是
d
!表达式
current_level=d
不复制
d
,它只是创建一个名为
current_level
;的对
d
的新引用。)如果
current\u level
是一个副本,上面的代码将不起作用,创建方式如下:
current\u level=d[:]
或类似这样:
current\u level=copy.deepcopy(d)
,但既然不是这样,它只会起作用@tsveti_iko如果它是一个参考,为什么行
current_level=current_level[部分]
只修改
current_level
,而不修改
d
?我已经检查了调试器,在这个阶段之后(例如,当我们在第一个元素
A
),我们将得到:
current_level={}
,而
d={'A':{}}
。谢谢