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
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.
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)
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.
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.
My answer is pretty similiar to @DonaldMiner's (In fact I started out with that as well), but then noticed that if a string in the list contains "["
or "]"
, it would fail.
E.g. won't work here:
["Hello", "World", "A", "[Menu]"]
I wrote a similiar function (a little more complex, and only removes the [
and ]
if it is not in a string in the list.
from ast import literal_eval
def flatten(to_squash):
"""This will flatten a list, no matter the recursion limit."""
instring = False
squashed = []
index = 0
print(repr(to_squash))
for char in repr(to_squash):
if char == '"' or char == "'":
instring = not instring
print(instring, char)
squashed.append(char)
elif not instring and char == "[" or not instring and char == "]":
pass
else:
squashed.append(char)
index += 1
print("".join([item.strip() for item in squashed]))
return literal_eval("".join(squashed))
You could of course also use eval()
, but only if you dont read in the list from somwhere (It is made by the program). Otherwise, someone can just enter a command, and python will execute it.
精彩评论