Reputation: 45
I created a function that will flatten a nested list into an ordinary list.
outputarray = []
def flattenarray(x):
for elmt in x:
if isinstance(elmt, float) or isinstance(elmt, int):
outputarray.append(elmt)
elif isinstance(elmt, list):
flattenarray(elmt)
return outputarray
The above works perfectly, but I am trying to have the "outputarray" variable inside the function, but when I do, the recursion step will overwrite the outputarray list back into an empty list.
How can I make this work to designate a list inside the function and at the same time be able to append to it without overwriting it during recursion?
Upvotes: 4
Views: 896
Reputation: 363123
You will want to create the output array from within the function. One way to proceed is to pass the output container along in the recursive step:
def flattenarray(x, outputarray=None):
if outputarray is None:
outputarray = []
for elmt in x:
if isinstance(elmt, float) or isinstance(elmt, int):
outputarray.append(elmt)
elif isinstance(elmt, list):
flattenarray(elmt, outputarray=outputarray)
return outputarray
A more Pythonic approach is for the flattener to yield the items one-by-one. Note that isinstance
can accept a tuple of types, so you only need to call it once.
def flatten(x):
for elmt in x:
if isinstance(elmt, (int, float, str, bytes)):
yield elmt
else:
yield from flatten(elmt)
A more correctly duck-typing implementation:
def flatten(x):
try:
it = iter(x)
except TypeError:
yield x
return
if isinstance(x, (str, bytes)):
yield x
return
for elem in it:
yield from flatten(elem)
Upvotes: 6
Reputation: 1518
This works perfectly with one line function and the basic idea is the same with wim:
def flatten(lst, outputarray=[]):
return sum( ([x] if not isinstance(x, (list,tuple)) else flatten(x)
for x in lst), outputarray)
lst=[1,2,3,[2,4,5,[6]],(7,8,9)]
print(flatten(lst))
Result:
[1, 2, 3, 2, 4, 5, 6, 7, 8, 9]
Upvotes: 2
Reputation: 114440
You could use the return value of your recursive function calls to extend the output instead of trying to insert into a global variable:
def flattenarray(x):
outputarray = []
for elmt in x:
if isinstance(elmt, float) or isinstance(elmt, int):
outputarray.append(elmt)
elif isinstance(elmt, list):
outputarray.extend(flattenarray(elmt))
return outputarray
This creates many more temporary lists than strictly necessary, so isn't very efficient. On the other hand, it's just as easy to read as your original code.
On a different note, I'd like to suggest a generalization to your code. Instead of checking for three specific types and skipping everything else, you can just check if an element is iterable or not:
global variable:
def flattenarray(x):
outputarray = []
for elmt in x:
try:
outputarray.extend(flattenarray(elmt))
except TypeError:
# the error will be raised by the for loop in the recursive call
outputarray.append(elmt)
return outputarray
Upvotes: 0