我正在使用Python,我有一些数据,我想将其放入树格式并分配代码。这是一些示例数据:
Africa North Africa Algeria
Africa North Africa Morocco
Africa West Africa Ghana
Africa West Africa Sierra Leone
这些数据的适当树结构是什么?
此外,有没有办法可以从这个树结构中检索数字代码,这样我就可以查询数据并得到如下例所示的代码?
def get_code(place_name):
# Python magic query to my tree structure
return code
get_code("Africa") # returns 1
get_code("North Africa") # returns 1.1
get_code("Morocco") # returns 1.1.2
感谢您的帮助 - 我仍然需要了解Python:)
答案 0 :(得分:9)
我建议,假设您可以指望名称之间没有重复,例如:
class Node(object):
byname = {}
def __init__(self, name, parent=None):
self.name = name
self.parent = parent
self.children = []
self.byname[name] = self
if parent is None: # root pseudo-node
self.code = 0
else: # all normal nodes
self.parent.children.append(self)
self.code = len(self.parent.children)
def get_codes(self, codelist):
if self.code:
codelist.append(str(self.code))
self.parent.get_codes(codelist)
root = Node('')
def get_code(nodename):
node = Node.byname.get(nodename)
if node is None: return ''
codes = []
node.get_codes(codes)
codes.reverse()
return '.'.join(codes)
您是否也希望看到如何在给定分层名称序列(例如['Africa', 'North Africa', 'Morocco']
)的情况下添加节点的Python代码?我希望鉴于上述结构会非常清楚,所以你可能想自己做一个练习,但当然要问你是否宁愿看一个解决方案; - )。
从文本行(字符串)获取名称的层次结构序列取决于分隔符是什么 - 在您的示例中,它看起来只是为了纯粹的美学原因添加了一堆空格,与排列列相关联(如果这是我推荐一种简单的基于re
的方法来分割两个+空格的序列),但如果它实际上是(例如)制表符作为分隔符,那么Python标准库中的csv
模块将会服务你好多了我从你在Q中发布的简短例子中无法分辨出来! - )
编辑:OP说他们可以很好地获取名称序列,但希望看到代码添加相关节点 - 所以,这里就是! - )
def addnodes(names):
parent = root
for name in names:
newnode = Node.byname.get(name)
if newnode is None:
newnode = Node(name, parent)
parent = newnode
了解为什么节点名称是唯一的,以使上述类工作?由于Node.byname
是单个每个类dict
,因此它只能为每个给定名称记录一个“对应节点” - 因此,在层次结构中的两个或多个位置重复的名称将“冲突” “并且只能正确记录两个或更多节点中的一个。
但是再说一次,如果一个名字可能含糊不清,那么OP所说的函数get_code
无法按照预期工作,因为OP的规格要求它只返回一个字符串。所以,像
America United States Georgia
Europe Eastern Europe Georgia
(其中两个完全不相关的区域发生都被命名为'Georgia'
- 正如上面的例子所显示的那样,不幸的是经常发生在现实世界的地理中! - )会破坏整个方案(取决于get_code
的规范如何被改变以处理模糊名称的论点,当然,类结构肯定会相应地改变并容纳新的,完全不同的规格!)。
将这些设计决策封装在一个类中是件好事(虽然在这种情况下有一些附带的函数 - 当然,它们可以优雅地用于类方法,但OP的规范严格要求{{1成为一个函数,所以我决定,在这种情况下get_code
也可能是一个! - )是特定的设计决策大部分隐藏在代码的其余部分,因此可以很容易地改变(当然,只要规格永远不会改变 - 这就是为什么花时间和注意力来定义一个API规范是非常重要的,远远超过任何设计和编码的其他部分! - )来重构内部行为(例如,用于优化,易于调试/测试等),同时保持API指定的语义完整,从而使应用程序的所有其他部分保持原始状态(实际上甚至不需要重新测试,当然实现API的部分经过了彻底的单元测试 - 不难做到,因为它们非常好孤立和独立! - )。
答案 1 :(得分:5)
表示树的ad-hoc POD(“普通旧数据”)类可以正常运行,例如:
class Location(object):
def __init__(self, data, parent)
self.data = data
self.parent = parent
self.children = []
现在可以使用辅助方法分配/读取data
属性,或添加/删除子项:
def add_child(self, child):
self.children.append(child)
现在,要实际将数据划分为树级别,一个简单的算法将查看具有公共级别数据(例如非洲)的所有位置,并为它们分配一个位置,然后递归地处理下一级数据。 / p>
因此,对于非洲,您创建一个数据=非洲的位置。然后,它将有一个位于北非,西非等地的孩子。
对于“获取代码”,有一个字典将每个国家/地区映射到其位置节点,并使用节点中的父链接。在每个级别从节点遍历到顶部(直到父级为None),将代码的一部分指定为父级子列表中的索引。
答案 2 :(得分:0)
我不确定,如果我做对了。如果我们将每个对象保存在全局字典中,那么它就会破坏使用树的目的,树只用于构造编号方案。 但基于树的表示看起来像这样:
class Location(object):
allLocation = {}
def __init__(self, name):
self.name = name
self.parent = None
self.number = "0"
self.children = {}
def putChild(self, childLocation):
if childLocation.name not in self.allLocation.keys():
# Now adjust the number scheme
#if self.number is "0":
# this is root
numScheme = str(len(self.children) + 1)
childLocation.setNumber(numScheme)
# Add the child
self.children[childLocation.number] = childLocation
self.allLocation[childLocation.name] = childLocation
childLocation.parent = self
return 0
else:
return 1 # Location already a child of the current clocation
def setNumber(self, num):
if self.number is not "0":
# raise an exception, number already adjusted
pass
else:
# set the number
self.number = num
def locateChild(self, numScheme):
# Logic should be to break up the numScheme and pass the token successively
numSchemeList = []
if type(numScheme) is str:
numSchemeList = numScheme.split(".")
else:
numSchemeList = numScheme
if len(numSchemeList) >= 1:
k = numSchemeList.pop()
# if the child is available
if k in self.children.keys():
childReferenced = self.children[k]
# Is child of child required
if len(numSchemeList) >= 1:
return childReferenced.locateChild(numSchemeList)
else:
return childReferenced
else:
# No such child
return None
else:
# The list is empty , search ends here
return None
def getScheme(self, name):
if name in self.allLocation.keys():
locObj = self.allLocation[name]
return locObj.getNumScheme(name, "")
else:
return None
def getNumScheme(self, name, numScheme="0",):
if not self.parent:
return numScheme
if numScheme != "":
return self.parent.getNumScheme(name, self.number + "." + numScheme)
else:
return self.parent.getNumScheme(name, self.number )
root = Location("root")
africa = Location("Africa")
asia = Location("Asia")
america = Location("America")
root.putChild(africa)
root.putChild(asia)
root.putChild(america)
nafrica = Location("North Africa")
africa.putChild(nafrica)
nafrica.putChild(Location("Morrocco"))
obj = root.locateChild("1.1.1")
print obj.name
print root.getScheme("Morrocco")
答案 3 :(得分:0)
此代码可能很糟糕。但是,我只是想粘贴它,因为我已经花了一些时间:)
tree = file_to_list_of_tuples(thefile)
d = {}
i = 1
for continent, region, country in tree:
if continent not in d:
d[continent] = [i, 0, 0]
i += 1
cont_code = d[continent][0]
if region not in d:
max_reg_code = max( [y for x, y, z in d.values() if x==cont_code] )
d[region] = [cont_code, max_reg_code+1 , 0]
reg_code = d[region][1]
if country not in d:
max_country_code = max( [z for x, y, z in d.values() if x == cont_code and y== reg_code] )
d[country] = [cont_code, reg_code, max_country_code+1]
def get_code(x):
print d[x]
get_code将打印列表,但您可以轻松地以所需格式打印它们。
答案 4 :(得分:0)
您可能会使用 itertree 包(我是作者):
from itertree import *
#1. create the tree:
root2=iTree('root')
root2.append(iTree('Africa'))
root2[0].append(iTree('North Africa'))
root2[0].append(iTree('West Africa'))
root2[0][0].append(iTree('Algeria'))
root2[0][0].append(iTree('Morocco'))
item=iTree('Ghana') # keep the item for easier access
root2[0][1].append(item)
root2[0][1].append(iTree('Sierra Leone'))
# get the index path information of an item:
print('"Ghana" item index path:',item.idx_path)
# you can also search for items:
result = root2.find(['**', 'Morroco'])
print('"Morroco" item index path:', result.idx_path)
执行脚本将交付:
"Ghana" item index path: [0, 1, 0]
"Morroco" item index path [0, 0, 1]
除此之外,您还可以向每个项目添加其他数据并进行过滤搜索。