views:

200

answers:

5

Is there a way to perform the following in a non-recursive fashion:

my_list = [
    "level 1-1",
    "level 1-2",
    "level 1-3",
        [
            "level 2-1",
            "level 2-2",
            "level 2-3",
            [
                "level 3-1",
                "level 3-2"
            ]
        ],
    "level 1-4",
    "level 1-5"
    ]


def print_list(the_list, indent_level=0):
    for item in the_list:
        if isinstance(item, list):
            print_list(item, indent_level + 1)
        else:
            print "\t" * indent_level, item


print_list(my_list)
+2  A: 
def print_list(the_list, indent_level=0):
    stack = [iter(the_list)]
    while stack:
        try:
            item = stack[-1].next()
        except StopIteration:
            stack.pop()
            indent_level -= 1
            continue
        if isinstance(item, list):
            indent_level += 1
            stack.append(iter(item))
        else:
            print "\t" * indent_level, item
Martin v. Löwis
A stack of iterators--cute. I like mine a bit better (concise, and slightly faster--for me, anyway), but this one avoids making a copy of the whole tree, which might be helpful if it's very large and broad. You'd probably need millions of nodes for it to matter, though.
Glenn Maynard
A: 

Note that this depens on the input not containing tuples.

l1 = my_list
done = False

# Repeatedly turn the list elements into tuples of the form
# (indent, item) until there are no more lists.
while not done:
    done = True
    l2 = []
    for item in l1:
        if isinstance(item,tuple):
            indent = item[0]
            item = item[1]
        else:
            indent = 0
        if isinstance(item,list):
            l2.extend( zip( (indent + 1,) * len(item), item) )
            done = False
        else:
            l2.append((indent,item))
    l1 = l2

for indent, item in l1:
    print "\t" * indent, item
balpha
+4  A: 
stack = [(my_list, -1)]
while stack:
    item, level = stack.pop()

    if isinstance(item, list):
        for i in reversed(item):
            stack.append((i, level+1))
    else:
        print "\t" * level, item
Glenn Maynard
A: 

Everyone has given solutions which are

  • production ready
  • use stack, so has same problem as recursion
  • or go thru list multiple time

Here is a solution lateral solution :)

  • not production ready but fun
  • no stack or anything like that, no lists in sight

--

def my_print(the_list):
    level = -1
    out = []
    levelUp="levelup"
    levelDown="leveldown"

    s =  repr(the_list).replace("', '","\n").replace(
        "', ['", "\n%s\n"%levelUp).replace("['", "\n%s\n"%levelUp).replace(
        "']", "\n%s\n"%levelDown).replace("], '", "\n%s\n"%levelDown)

    for line in s.splitlines():
        if not line: continue
        if line == levelUp:
            level+=1
        elif line == levelDown:
            level-=1
        else:
            print "\t"*level,line

my_print(my_list)

It assumes the your list text will not have some special substrings.

Anurag Uniyal
+2  A: 

Here's a variation of Martin Löwis' version that uses for/else instead of manually catching StopIteration, and len(stack) instead of keeping track of the indent level.

def print_list(the_list):
    stack = [iter(the_list)]
    while stack:
        for item in stack[-1]:
            if isinstance(item, (list, tuple)):
                stack.append(iter(item))
                break
            else:
                print '\t' * (len(stack)-1), item
        else:
            stack.pop()
Ivan Baldin