Python nested lists

I am trying to solve a problem that, unfortunately, is beyond my capabilities. I have a number of nested lists and iterate over them, in case the next element is a list, I want to add it as an attribute of my current element. As usual, the example is better than my bad English (there is code for copy and paste):

class T(object): def __init__(self, id, children): self.id = id self.children = children or [] def __repr__(self): return u"T(id={0}, children={1})".format(self.id, self.children) # first a short example l0 = [T(id=1, children=[]), T(id=2, children=[]), [T(id=3, children=[]), T(id=4, children=[]), [T(id=5, children=[])]]] 

As you can see, l0 has 3 elements, and the last one is a list of three elements: I need to add the last list to the previous element, which is not a list (and recursively) Expected result:

 l1 = magic(l0) [T(id=1, children=[]), T(id=2, children=[T(id=3, children=[]), T(id=4, children=[T(id=5, children=[])])])] 

Hope someone can share some tips to resolve this issue, I have already spent many hours and I canโ€™t even solve it.

EDIT

For completeness, here is a slightly more complex example.

 l0 = [T(children=[], id=1), T(children=[], id=2), T(children=[], id=3), [T(children=[], id=40), T(children=[], id=41), T(children=[], id=42), T(children=[], id=43), T(children=[], id=44), T(children=[], id=45), [T(children=[], id=50), T(children=[], id=51), T(children=[], id=52), T(children=[], id=54), [T(children=[], id=60), T(children=[], id=61), T(children=[], id=62), T(children=[], id=63), [T(children=[], id=70)], T(children=[], id=64)]]], T(children=[], id=8), T(children=[], id=9)] 

I built a teaching using the @ rik-poggi function as an example, and so far it looks fine:

 >>> from magic_bag import magic >>> class T(object): ... def __init__(self, id, children): ... self.id = id ... self.children = children or [] ... ... def __repr__(self): ... return u"T(children={0}, id={1})".format(self.children, self.id) ... >>> l0 = [T(id=1, children=[]), T(id=2, children=[]), T(id=3, children=[]), ... [T(id=40, children=[]), T(id=41, children=[]), T(id=42, children=[]), ... T(id=43, children=[]), T(id=44, children=[]), T(id=45, children=[]), ... [T(id=50, children=[]), T(id=51, children=[]), T(id=52, children=[]), ... T(id=54, children=[]), [T(id=60, children=[]), T(id=61, children=[]), ... T(id=62, children=[]), T(id=63, children=[])]]], T(id=8, children=[]), ... T(id=9, children=[])] >>> l1 = magic(l0) >>> l1[0] T(children=[], id=1) >>> l1[1] T(children=[], id=2) >>> l1[3] T(children=[], id=8) >>> l1[4] T(children=[], id=9) >>> l1[5] Traceback (most recent call last): ... IndexError: list index out of range >>> l1[2].children[5].children[3] T(children=[T(children=[], id=60), T(children=[], id=61), T(children=[], id=62), T(children=[], id=63)], id=54) >>> l0 = [T(id=1, children=[]), T(id=2, children=[]), T(id=3, children=[]), ... [T(id=40, children=[]), T(id=41, children=[]), T(id=42, children=[]), ... T(id=43, children=[]), T(id=44, children=[]), T(id=45, children=[]), ... [T(id=50, children=[]), T(id=51, children=[]), T(id=52, children=[]), ... T(id=54, children=[]), [T(id=60, children=[]), T(id=61, children=[]), ... T(id=62, children=[]), T(id=63, children=[]), [T(id=70, children=[])], ... T(id=64, children=[])]]], T(id=8, children=[]), T(id=9, children=[])] >>> l1 = magic(l0) >>> l1[2].children[5].children[0].id 50 >>> len(l1[2].children[5].children[3].children) 5 >>> l1[2].children[5].children[3].children[3].children [T(children=[], id=70)] >>> l1[2].children[5].children[3].children[4].id==64 True 

Using the @ rob-wouters alternative, it passes the same test, so both test cases work fine for the test cases I tried. I will keep Rick, because I think that a standalone function might be more convenient for cases when I need this behavior.

+4
source share
2 answers

I came up with this:

 def append_children(parent, iterable): last = None for i in iterable: if hasattr(i, '__iter__'): append_children(last, i) else: parent.children.append(i) last = i def magic(lst): result = [] for i in lst: if hasattr(i, '__iter__'): append_children(result[-1], i) else: result.append(i) return result 

Example:

 >>> l_in = [T(id=1, children=[]), T(id=2, children=[]), [T(id=3, children=[]), ... T(id=4, children=[]), [T(id=5, children=[])]]] >>> l_expected = [T(id=1, children=[]), ... T(id=2, children=[T(id=3, children=[]), ... T(id=4, children=[T(id=5, children=[])])])] >>> l_ouput = magic(l_in) >>> repr(l_output) == repr(l_expected) True 
+1
source

Here's how I do it:

 class T(object): def __init__(self, id, children): self.id = id self.children = children or [] def add_children(self, children): for child in children: if isinstance(child, list): self.children[-1].add_children(child) else: self.children.append(child) def __repr__(self): return u"T(id={0}, children={1})".format(self.id, self.children) l0 = [T(id=1, children=[]), T(id=2, children=[]), [T(id=3, children=[]), T(id=4, children=[]), [T(id=5, children=[])]]] root = T(id=0, children=[]) root.add_children(l0) print(root.children) 

If you really need a stand-alone method, instead of two functions that handle the same case, you can use the following:

 def add_children(node, children): for child in children: if hasattr(child, '__iter__'): add_children(node.children[-1], child) else: node.children.append(child) def create_tree(lst): root = T(id=0, children=[]) add_children(root, lst) return root.children print(create_tree(l0)) 

This is a bit more elegant since it avoids a lot of repetitive code compared to the fact that the two functions are almost the same. I changed my isinstance check to a check on __iter__ , which allows more flexibility in how you keep your childrenโ€™s list.

+3
source

Source: https://habr.com/ru/post/1391358/


All Articles