Reputation: 681
Below is the node class definition with tree structure (built using node instance) of programming languages. Now how to convert hierarchical node data tree structure to python dictionary using node class method ? See desired output at bottom.
class Node(object):
def __init__(self, name, parent=None):
self._name = name
self._children = []
self._parent = parent
if parent is not None:
parent.addChild(self)
def addChild(self, child):
self._children.append(child)
def name(self):
return self._name
def setName(self, name):
self._name = name
def child(self, row):
return self._children[row]
def childCount(self):
return len(self._children)
def parent(self):
return self._parent
rootNode = nodeData.Node("books")
web_node = nodeData.Node("web", rootNode)
database_node = nodeData.Node("database", rootNode)
front_end_node = nodeData.Node("front-end", web_node)
back_end_node = nodeData.Node("back-end", web_node)
sql_node = nodeData.Node("sql", database_node)
nosql_node = nodeData.Node("nosql", database_node)
html_node = nodeData.Node("html", front_end_node)
css_node = nodeData.Node("css", front_end_node)
js_node = nodeData.Node("js", front_end_node)
php_node = nodeData.Node("php", back_end_node)
python_node = nodeData.Node("python", back_end_node)
mysql_node = nodeData.Node("mysql", sql_node)
postgresql_node = nodeData.Node("postgresql", sql_node)
mongodb_node = nodeData.Node("mongodb", nosql_node)
cassandra_node = nodeData.Node("cassandra", nosql_node)
html_book_one_node = nodeData.Node("the missing manual", html_node)
html_book_two_node = nodeData.Node("core html5 canvas", html_node)
css_book_one_node = nodeData.Node("css pocket reference", css_node)
css_book_two_node = nodeData.Node("css in depth", css_node)
js_book_one_node = nodeData.Node("you don't know js", js_node)
js_book_two_node = nodeData.Node("eloquent javascript", js_node)
php_book_one_node = nodeData.Node("modern php", php_node)
python_book_one_node = nodeData.Node("dive into python", python_node)
python_book_two_node = nodeData.Node("python for everybody", python_node)
python_book_three_node = nodeData.Node("Think Python", python_node)
mongodb_book_one_node = nodeData.Node("mongodb in action", mongodb_node)
mongodb_two_node = nodeData.Node("scaling mongodb", mongodb_node)
From node tree abstraction to python dictionary
{"books":{ "web":{ "front-end":{ "html":["the missing manual", "core html5 canvas"], "css":["css pocket reference", "css in depth"], "js":["you don't know js", "eloquent javascript"] }, "back-end":{ "php":["modern php"], "python":["dive into python", "python for everybody", "Think Python"] } }, "database":{ "sql":{ "mysql":[], "postgresql":[] }, "nosql":{ "mongodb":["mongodb in action", "scaling mongodb"], "cassandra":[] }}}}
class Node(object):
def __init__(self, name, parent=None):
self._name = name
self._children = []
self._parent = parent
if parent is not None:
parent.addChild(self)
def addChild(self, child):
self._children.append(child)
def name(self):
return self._name
def setName(self, name):
self._name = name
def child(self, row):
return self._children[row]
def childCount(self):
return len(self._children)
def parent(self):
return self._parent
class categoryNode(Node):
def __init__(self, name, parent=None):
super(categoryNode, self).__init__(name, parent)
class subCategoryNode(Node):
def __init__(self, name, parent=None):
super(subCategoryNode, self).__init__(name, parent)
class languageNode(Node):
def __init__(self, name, parent=None):
super(languageNode, self).__init__(name, parent)
class BookNode(Node):
def __init__(self, name, parent=None):
super(BookNode, self).__init__(name, parent)
rootNode = Node("books")
web_node = categoryNode("web", rootNode)
database_node = categoryNode("database", rootNode)
front_end_node = subCategoryNode("front-end", web_node)
back_end_node = subCategoryNode("back-end", web_node)
sql_node = subCategoryNode("sql", database_node)
nosql_node = subCategoryNode("nosql", database_node)
html_node = languageNode("html", front_end_node)
css_node = languageNode("css", front_end_node)
js_node = languageNode("js", front_end_node)
php_node = languageNode("php", back_end_node)
python_node = languageNode("python", back_end_node)
mysql_node = languageNode("mysql", sql_node)
postgresql_node = languageNode("postgresql", sql_node)
mongodb_node = languageNode("mongodb", nosql_node)
cassandra_node = languageNode("cassandra", nosql_node)
html_book_one_node = BookNode("the missing manual", html_node)
html_book_two_node = BookNode("core html5 canvas", html_node)
css_book_one_node = BookNode("css pocket reference", css_node)
css_book_two_node = BookNode("css in depth", css_node)
js_book_one_node = BookNode("you don't know js", js_node)
js_book_two_node = BookNode("eloquent javascript", js_node)
php_book_one_node = BookNode("modern php", php_node)
python_book_one_node = BookNode("dive into python", python_node)
python_book_two_node = BookNode("python for everybody", python_node)
python_book_three_node = BookNode("Think Python", python_node)
mongodb_book_one_node = BookNode("mongodb in action", mongodb_node)
mongodb_two_node = BookNode("scaling mongodb", mongodb_node)
Upvotes: 3
Views: 938
Reputation: 51162
You have a bigger problem, because you're using the same class to represent both book categories and actual books. Given this, it is impossible to programmatically determine that mysql_node
and postgresql_node
are empty categories rather than books.
To make this work how you want, you will need to redesign the data structure. I suggest having a list _children
for subcategories and another list _books
for book titles (as strings). Note that this data structure is still a little ambiguous because a node with no subcategories and no books could be rendered as an empty list (i.e. a terminal category with no books) or an empty dictionary (i.e. a non-terminal category with no subcategories); I infer from the question that an empty list is the desired result.
class Node:
def __init__(self, name, parent=None):
self._name = name
self._children = []
self._parent = parent
self._books = []
if parent is not None:
parent.addChild(self)
def name(self):
return self._name
def setName(self, name):
self._name = name
def parent(self):
return self._parent
def addChild(self, child):
if self._books:
raise ValueError('Node cannot have both sub-categories and books')
self._children.append(child)
def child(self, row):
return self._children[row]
def childCount(self):
return len(self._children)
def addBook(self, book):
if self._children:
raise ValueError('Node cannot have both sub-categories and books')
self._books.append(book)
def book(self, row):
return self._books[row]
def bookCount(self):
return len(self._books)
rootNode = Node("books")
web_node = Node("web", rootNode)
database_node = Node("database", rootNode)
front_end_node = Node("front-end", web_node)
back_end_node = Node("back-end", web_node)
sql_node = Node("sql", database_node)
nosql_node = Node("nosql", database_node)
html_node = Node("html", front_end_node)
css_node = Node("css", front_end_node)
js_node = Node("js", front_end_node)
php_node = Node("php", back_end_node)
python_node = Node("python", back_end_node)
mysql_node = Node("mysql", sql_node)
postgresql_node = Node("postgresql", sql_node)
mongodb_node = Node("mongodb", nosql_node)
cassandra_node = Node("cassandra", nosql_node)
html_node.addBook("the missing manual")
html_node.addBook("core html5 canvas")
css_node.addBook("css pocket reference")
css_node.addBook("css in depth")
js_node.addBook("you don't know js")
js_node.addBook("eloquent javascript")
php_node.addBook("modern php")
python_node.addBook("dive into python")
python_node.addBook("python for everybody")
python_node.addBook("Think Python")
mongodb_node.addBook("mongodb in action")
mongodb_node.addBook("scaling mongodb")
def node_to_dict(node):
def helper(n):
if n.childCount() > 0:
return { c.name(): helper(c) for c in n._children }
else:
return list(n._books)
return { node.name(): helper(node) }
The result of node_to_dict(rootNode)
does ==
your expected output.
Upvotes: 1
Reputation: 71471
Simple recursive function:
def to_dict(node):
if isinstance(node, nodeData.Node):
return {node._name:to_dict(node._children)}
if all(isinstance(i, nodeData.Node) for i in node):
return (lambda x:x if all(x.values()) else list(x))({i._name:to_dict(i._children) for i in node})
return node
print(to_dict(rootNode))
Output:
{'books': {'web': {'front-end': {'html': ['the missing manual', 'core html5 canvas'], 'css': ['css pocket reference', 'css in depth'], 'js': ["you don't know js", 'eloquent javascript']}, 'back-end': {'php': ['modern php'], 'python': ['dive into python', 'python for everybody', 'Think Python']}}, 'database': {'sql': ['mysql', 'postgresql'], 'nosql': ['mongodb', 'cassandra']}}}
Upvotes: 0