【问题标题】:Creating Nested Dictionary from File hierarchy从文件层次结构创建嵌套字典
【发布时间】:2016-05-06 09:07:36
【问题描述】:

我想知道是否有人可以为我指明正确的方向。我试图从文件路径列表中创建一个嵌套字典,如下所示。这个列表会根据用户的输入而改变,所以我想它需要是递归的。关于从哪里开始的任何指示?

编辑:此外,字典将被转换为 JSON 并用于使用 D3.js 创建图表。

fileDict = [
    {
        "name": "BaseLevel",
        "children": [
          {
            "name": "/etc/",
            "children": [
              {
                "name": "/etc/passwd",
              },
              {
                "name": "/etc/group"
              }
            ]
          },
          {
            "name": "/root/",
            "children": [
              {
                "name": "/root/test",
              }
            ]
          }
        ]
      }
    ]

我能得到的最接近的例子就是这个

    records = ["base/images/graphs/one.png", "base/images/tikz/two.png",
"base/refs/images/three.png", "base/one.txt", "base/chapters/two.txt"]

recordsSplit = map(lambda x: x.split("/"), records)

for record in recordsSplit:
    here = result
    for item in record[:-1]:
        if not item in here:
            here[item] = {}
            here = here[item]
        if "###content###" not in here:
            here["###content###"] = []
            here["###content###"].append(record[-1])

print json.dumps(result, indent=4)

【问题讨论】:

  • 您的示例仅显示一个级别。您是尝试仅按第一级目录对路径进行分类,还是构建嵌套字典的“树”,并为路径的每一级使用单独的字典?
  • 尝试构建嵌套字典树。我的目标是最终得到一个 d3.js 图表,其中的树结构代表文件层次结构

标签: python file dictionary nested hierarchy


【解决方案1】:

创建一个类而不是一个字典值得吗?写了一个简短的,应该做你想做的事

class FileSystem():
    
    def __init__(filePath=None):
        self.children = []
        if files != None:
            try:
                self.name, child = files.split("/", 2)
                self.children.append(FileSystem(filePath))
            except (ValueError):
                 pass
            
    def addChild(filePath):
        self.children.append(FileSystem(filePath))
    
    def getChildren():
        return self.children

    def printAllChildren():
        print "Name: "+ self.name
        print "{ Children:"
        for child in self.children:
            child.printAllChildren()
        print "}"

然后您可以输入第一个路径并保存对它的引用

myFileSystem = FileSystem("base/pictures/whatever.png")

这个myFileSystem 将是您对“基础”级别的引用,使用它和它的方法您应该能够做您想做的事。

然后,当您有第二条路径要添加时,您必须通过在 myFileSystem 上使用 getChildren() 找到正确的节点来添加它,直到找到差异,然后使用 addChild() 添加其余的该节点的文件路径。 然后使用myFileSystem.printAllChildren() 会打印出整个文件系统。

-------编辑-------

对我写了一半的代码不太满意,喜欢挑战,所以这里有一个易于使用的课程

class FileSystem():

    def __init__(self,filePath=None):
        self.children = []
        if filePath != None:
            try:
                self.name, child = filePath.split("/", 1)
                self.children.append(FileSystem(child))
            except (ValueError):
                self.name = filePath
            
    def addChild(self, filePath):
        try:
            thisLevel, nextLevel = filePath.split("/", 1)
            try:
                if thisLevel == self.name:
                    thisLevel, nextLevel = nextLevel.split("/", 1)
            except (ValueError):
                self.children.append(FileSystem(nextLevel))
                return
            for child in self.children:
                if thisLevel == child.name:
                    child.addChild(nextLevel)
                    return
            self.children.append(FileSystem(nextLevel))
        except (ValueError):
            self.children.append(FileSystem(filePath))

    def getChildren(self):
        return self.children
        
    def printAllChildren(self, depth = -1):
        depth += 1
        print "\t"*depth + "Name: "+ self.name
        if len(self.children) > 0:
            print "\t"*depth +"{ Children:"
            for child in self.children:
                child.printAllChildren(depth)
            print "\t"*depth + "}"
        
records = ["base/images/graphs/one.png", "base/images/tikz/two.png",
"base/refs/images/three.png", "base/one.txt", "base/chapters/two.txt"]

myFiles = FileSystem(records[0])
for record in records[1:]:
    myFiles.addChild(record)

myFiles.printAllChildren()      

正如您在最后看到的那样,当我简单地执行myFiles.addChild(record) 时,addChild 函数现在负责在树中找到正确的位置供它进入。 printAllChildren() 至少为那些提供了正确的输出参数。

如果其中任何一个没有意义,请告诉我,就像我说它没有经过全面测试,所以一些极端情况(例如,尝试添加另一个基础?)可能会让它变得很奇怪。

EDIT2

class FileSystem():

    def __init__(self,filePath=None):
        self.children = []
        if filePath != None:
            try:
                self.name, child = filePath.split("/", 1)
                self.children.append(FileSystem(child))
            except (ValueError):
                self.name = filePath

    def addChild(self, filePath):
        try:
            thisLevel, nextLevel = filePath.split("/", 1)
            try:
                if thisLevel == self.name:
                    thisLevel, nextLevel = nextLevel.split("/", 1)
            except (ValueError):
                self.children.append(FileSystem(nextLevel))
                return
            for child in self.children:
                if thisLevel == child.name:
                    child.addChild(nextLevel)
                    return
            self.children.append(FileSystem(nextLevel))
        except (ValueError):
            self.children.append(FileSystem(filePath))

    def getChildren(self):
        return self.children

    def printAllChildren(self, depth = -1):
        depth += 1
        print "\t"*depth + "Name: "+ self.name
        if len(self.children) > 0:
            print "\t"*depth +"{ Children:"
            for child in self.children:
                child.printAllChildren(depth)
            print "\t"*depth + "}"
            
    def makeDict(self):
        if len(self.children) > 0:
            dictionary = {self.name:[]}
            for child in self.children:
                dictionary[self.name].append(child.makeDict())
            return dictionary
        else:
            return self.name
                

records = ["base/images/graphs/one.png", "base/images/tikz/two.png",
"base/refs/images/three.png", "base/one.txt", "base/chapters/two.txt"]

myFiles = FileSystem(records[0])
for record in records[1:]:
    myFiles.addChild(record)

print myFiles.makeDict()      

【讨论】:

  • 这个答案太棒了,绝对有帮助,所以谢谢。不幸的是,我没有提到的错误,它必须是字典,因为它需要转换为 JSON,并使用 D3.js 显示
  • 哦,我明白了,对不起,我应该阅读您的尝试,您在那里有一个 json 关键字。不幸的是,我对 JSON 了解不多,但是您绝对可以将我的解决方案塑造成一个实际的 dict。一种方法是扩展 dict 类(字面上将类声明为class FileSystem(dict):,然后编辑当前方法,使self.name 设置为键,self.children 设置为值。或者有一个@ 987654335@ 方法,该方法构建并返回一个字典(与 printAll() 当前的方式类似),通过将 self.name 设置为键和 self.children 作为值。
  • 如果没有其他人提出任何建议,我可以稍后再尝试
  • 见编辑 2,有点匆忙,但我认为它有效。
  • 抱歉回复晚了,我周末不在。您的第二次编辑效果很好,非常感谢!
【解决方案2】:

当你有这样的文件时:

['testdata/hhohoho.mdf', 'testdata/dvojka/rerere.bdf', 'testdata/jedna/sss.txt']

你的输出结构如下:

Name: testdata
{ Children:
    Name: hhohoho.mdf
    Name: rerere.bdf
    Name: sss.txt
}

你有一个错误:

self.children.append(FileSystem(nextLevel))
    except (ValueError):
        self.children.append(FileSystem(filePath))

解决如下:

 self.children.append(FileSystem(thisLevel))
        for child in self.children:
            if thisLevel == child.name:
                child.addChild(nextLevel)
                return


Name: testdata
{ Children:
    Name: hhohoho.mdf
    Name: dvojka
    { Children:
            Name: rerere.bdf
    }
    Name: jedna
    { Children:
            Name: sss.txt
    }
}

【讨论】: