Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Edit</strong>: thanks to the clarification and change in the spec I've edited my code, still using an explicit <code>Node</code> class as an intermediate step for clarity -- the logic is to turn the list of lines into a list of nodes, then turn that list of nodes into a tree (by using their indent attribute appropriately), then print that tree in a readable form (this is just a "debug-help" step, to check the tree is well constructed, and can of course get commented out in the final version of the script -- which, just as of course, will take the lines from a file rather than having them hardcoded for debugging!-), finally build the desired Python structure and print it. Here's the code, and as we'll see after that the result is <em>almost</em> as the OP specifies with one exception -- but, the code first:</p> <pre><code>import sys class Node(object): def __init__(self, title, indent): self.title = title self.indent = indent self.children = [] self.notes = [] self.parent = None def __repr__(self): return 'Node(%s, %s, %r, %s)' % ( self.indent, self.parent, self.title, self.notes) def aspython(self): result = dict(title=self.title, children=topython(self.children)) if self.notes: result['notes'] = self.notes return result def print_tree(node): print ' ' * node.indent, node.title for subnode in node.children: print_tree(subnode) for note in node.notes: print ' ' * node.indent, 'Note:', note def topython(nodelist): return [node.aspython() for node in nodelist] def lines_to_tree(lines): nodes = [] for line in lines: indent = len(line) - len(line.lstrip()) marker, body = line.strip().split(None, 1) if marker == '*': nodes.append(Node(body, indent)) elif marker == '-': nodes[-1].notes.append(body) else: print&gt;&gt;sys.stderr, "Invalid marker %r" % marker tree = Node('', -1) curr = tree for node in nodes: while node.indent &lt;= curr.indent: curr = curr.parent node.parent = curr curr.children.append(node) curr = node return tree data = """\ * 1 * 1.1 * 1.2 - Note for 1.2 * 2 * 3 - Note for root """.splitlines() def main(): tree = lines_to_tree(data) print_tree(tree) print alist = topython(tree.children) print alist if __name__ == '__main__': main() </code></pre> <p>When run, this emits:</p> <pre><code> 1 1.1 1.2 Note: 1.2 2 3 Note: 3 [{'children': [{'children': [], 'title': '1.1'}, {'notes': ['Note for 1.2'], 'children': [], 'title': '1.2'}], 'title': '1'}, {'children': [], 'title': '2'}, {'notes': ['Note for root'], 'children': [], 'title': '3'}] </code></pre> <p>Apart from the ordering of keys (which is immaterial and not guaranteed in a dict, of course), this is <em>almost</em> as requested -- except that here <strong>all</strong> notes appear as dict entries with a key of <code>notes</code> and a value that's a list of strings (but the notes entry is omitted if the list would be empty, roughly as done in the example in the question).</p> <p>In the current version of the question, how to represent the notes is slightly unclear; one note appears as a stand-alone string, others as entries whose value is a string (instead of a list of strings as I'm using). It's not clear what's supposed to imply that the note must appear as a stand-alone string in one case and as a dict entry in all others, so this scheme I'm using is more regular; and if a note (if any) is a single string rather than a list, would that mean it's an error if more than one note appears for a node? In the latter regard, this scheme I'm using is more general (lets a node have any number of notes from 0 up, instead of just 0 or 1 as apparently implied in the question).</p> <p>Having written so much code (the pre-edit answer was about as long and helped clarify and change the specs) to provide (I hope) 99% of the desired solution, I hope this satisfies the original poster, since the last few tweaks to code and/or specs to make them match each other should be easy for him to do!</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload