tags:

views:

68

answers:

4

I'm doing an exercise to flatten nested lists. The code works in console but it doesn't work when its in a file. I have no idea what's going on. :(

def flatten(nested):
    """
            >>> flatten([2, 9, [2, 1, 13, 2], 8, [2, 6]])
            [2, 9, 2, 1, 13, 2, 8, 2, 6]
            >>> flatten([[9, [7, 1, 13, 2], 8], [7, 6]])
            [9, 7, 1, 13, 2, 8, 7, 6]
            >>> flatten([[9, [7, 1, 13, 2], 8], [2, 6]])
            [9, 7, 1, 13, 2, 8, 2, 6]
            >>> flatten([[5, [5, [1, 5], 5], 5], [5, 6]])
            [5, 5, 1, 5, 5, 5, 5, 6]
    """
    simple = []

    for x in nested:
            if type(x) == type([]):
                    for y in x:
                            simple.append(y)
            else:
                    simple.append(x)
    return simple



if __name__ == '__main__':
    import doctest
    doctest.testmod()

I first tried to solve this exercise recursively but decided to try it iterative first.

edit: When executed in the file it just prints out the original function argument TIA

+5  A: 

The problem is that your flatten function only flattens one level. The reason why doctest is printing out errors is because it is indeed erroring. They are not what you passed in.

File "test.py", line 5, in __main__.flatten
Failed example:
    flatten([[9, [7, 1, 13, 2], 8], [7, 6]])
Expected:
    [9, 7, 1, 13, 2, 8, 7, 6]
Got:
    [9, [7, 1, 13, 2], 8, 7, 6]

You should investigate a recursive approach that instead of appending y--- you call flatten on y as well. if type(x) != type([]) can be your base case.

orangeoctopus
A: 

Your application is not doing nothing.

Input:  [3,[5, [5, [1, 5], 5], 5], [5, 6]]
Output: [3, 5, [5, [1, 5], 5], 5 ,  5, 6]

You need to keep flattening until it completes, e.g. using recursion. Simple but with one extra pass over your data: If type(x) == type([]), return flatten(simple) instead of simple at the end of the function.

Brian
A: 

I think that @orangeoctopus's answer is correct, but doesn't capture the "why does it work in the console" question. I'm going to make a guess:

It doesn't work in the console. I think you tested with a subset of the input that happens to work. For example,

>>> flatten([2, 9, [2, 1, 13, 2], 8, [2, 6]])
[2, 9, 2, 1, 13, 2, 8, 2, 6]

works!

But

>>> flatten([[9, [7, 1, 13, 2], 8], [7, 6]])
[9, [7, 1, 13, 2], 8, 7, 6]

does not so much.

Blair Conrad
+2  A: 

If you want to "cheat" you could do this:

L = [1, 2, [3, 4], 5, 6, [7, 8, [9, 10, 11]]]
s = repr(L)
s = '[' + s.replace('[','').replace(']','') + ']'
L = eval(s)

I'm kind of curious how fast that would be compared to the "normal" flattening operation...


Edit:

A cursory test shows that the cheating method takes nearly constant time regardless of data complexity, while a recursive solution increases in time.

Larger

Cheat: 7.13282388182
Recurse: 2.84676811407

Smaller

Cheat: 7.08800692623
Recurse: 0.486098086038

Here's my code (and I'm really curious about larger data sets!):

import timeit

L = [1,2,3,
     [46, 100000, 20, 9, 
      [1,2,3, 
       [9, 23, 24, 
        [9, 23, 24, 
         [9, 23, 24, 
          [9, 23, 24, 
           [9, 23, 24, [9, 23, 24, [13], 12],4]]]], 26]]]]

L2 = [1,2,3, [4,5,6]]

def flattencheat(mylist):
    s = repr(L)
    s = '[' + s.replace('[', '').replace(']', '') + ']'
    return eval(s)

def flattencurse(mylist):
    newlist = []
    for val in mylist:
        if not hasattr(val, '__iter__'):
            newlist.append(val)
        else:
            newlist.extend(flattencurse(val))

    return newlist

print "Cheat: ", timeit.timeit('flattencheat(L)', "from __main__ import flattencheat, L", number=100000)
print "Recurse: ", timeit.timeit('flattencurse(L)', 
                                 'from __main__ import flattencurse, L',
                                 number = 100000)
print "Cheat: ", timeit.timeit('flattencheat(L2)', "from __main__ import flattencheat, L2", number=100000)
print "Recurse: ", timeit.timeit('flattencurse(L2)', 
                                 'from __main__ import flattencurse, L2',
                                 number = 100000)
Wayne Werner
This is awesome.
orangeoctopus
Check out the test results...
Wayne Werner
Hmm... what happens if one of the elements is dictionary or object?
Nas Banov
In the recursive test it will flatten the keys only. As for object, it depends on how and if it implements __repr__ and __iter__. Not a robust solution by any means, but the OP's specific request was dealing with nested lists.
Wayne Werner