Posts: 66
Threads: 19
Joined: Nov 2018
Nov-24-2018, 07:04 PM
(This post was last modified: Nov-24-2018, 07:04 PM by dan789.)
Hello, I have one trouble in my program I´m currently working on. I need to make a function, which flatten a list whom items can contain lists again, into a one simple list. Function gets a list as a parameter and I need to return new flattened list without changing the main one, using recursion.
This is my current attempt:
1 2 3 4 5 6 7 8 9 |
result = []
def flatten(nested_list):
for i in nested_list:
if type (i) ! = list :
result.append(i)
else :
flatten(i)
return result
|
The problem here is, as soon as I want to run this function again, it remembers the last result, what means that it appends everything at the end. But I want to make a new result, containing just a simple list of current nested one. How can I remove last result when calling function again?
Thanks.
Posts: 2,342
Threads: 62
Joined: Sep 2016
There are different solutions, but I prefer to use a closure and a helper function like so
1 2 3 4 5 6 7 8 9 10 11 12 |
def flatten(to_flatten):
result = []
def helper(nested_list):
for i in nested_list:
if type (i) ! = list :
result.append(i)
else :
helper(i)
return result
return helper(to_flatten)
|
Alternatively, you could have a second parameter which defaults to None, and you have have logic which creates the result variable when that parameter is None and then provide it for the recursive calls. I prefer the method I've coded here because it does not change the interface given to clients of the code, who might accidentally provide a second parameter (or who might notice it and wonder).
Posts: 66
Threads: 19
Joined: Nov 2018
Nov-24-2018, 08:01 PM
(This post was last modified: Nov-24-2018, 08:01 PM by dan789.)
Thanks for your help. But, I fear that the first solution you described is not entirely appropriate for my program. There should stay 1 function, no more.
And about second solution - can you please describe it a bit more, it´s not very clear for me, what exactly you mean.
Posts: 4,220
Threads: 97
Joined: Sep 2016
If you never want to save the result for the next call, just put result = [] as the first statement inside the function, rather than outside the function.
Posts: 66
Threads: 19
Joined: Nov 2018
But when I make it like this:
1 2 3 4 5 6 7 8 |
def flatten(nested_list):
result = []
for i in nested_list:
if type (i) ! = list :
result.append(i)
else :
flatten(i)
return result
|
it clears the list every time when calling a recursion. So from input flatten([0,1,2,[3,4]]) I get output just [0,1,2]
Posts: 2,128
Threads: 11
Joined: May 2017
Nov-24-2018, 09:10 PM
(This post was last modified: Nov-24-2018, 09:16 PM by DeaD_EyE.)
If you have only a nested list, not a deep nested list, you can use itertools.chain.from_iterable
1 2 3 4 5 6 7 8 |
from itertools import chain
flatten = chain.from_iterable
nested = [( 'a' , 'b' , 'r' , 'a' ),( 'c' , 'a' , 'd' , 'a' , 'b' , 'r' , 'a' )]
result = list (flatten(nested))
print (result)
|
Output: ['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']
chain.from_iterable returns an iterator. You have to consume this iterator to result by result.
If you always want to have a list as result, you can make a function for it.
1 2 3 4 5 6 7 8 9 10 |
from itertools import chain
def flatten_to_list(iterable):
return list (chain.from_iterable(iterable))
nested = [( 'a' , 'b' , 'r' , 'a' ),( 'c' , 'a' , 'd' , 'a' , 'b' , 'r' , 'a' )]
print (flatten_to_list(nested))
|
Output: ['a', 'b', 'r', 'a', 'c', 'a', 'd', 'a', 'b', 'r', 'a']
Reference from Python documentation: itertools itertools-recipes
Do you like it? You should read the whole description of this module. It's very powerful. Mostly all parts of Python language have implemented iteration. The benefit is also, that you can work with "big data" or data-streams. The iterator protocol allows this. The function flatten_to_list removes this ability, because the list is constructed in memory until the iteration ends. It's not possible with infinite streams, except if you use itertools.islice(iterable, start, end) .
In addition, you get back, what you want. If you want to have a set , then use set(chain.from_iterable(nested_something)) .
This can be done also with tuple , list , dict.fromkeys and other types which consumes iterables.
Bonus: You can do it also with str.join
1 2 3 4 5 6 |
result1 = str .join( '-' , flatten(nested))
result2 = '-' .join(flatten(nested))
print (result1)
print (result2)
|
Output: a-b-r-a-c-a-d-a-b-r-a
a-b-r-a-c-a-d-a-b-r-a
Posts: 4,220
Threads: 97
Joined: Sep 2016
Sorry, missed the recursion. My bad.
Posts: 4,220
Threads: 97
Joined: Sep 2016
This should do it:
1 2 3 4 5 6 7 8 |
def flatten(nested_list):
result = []
for i in nested_list:
if type (i) ! = list :
result.append(i)
else :
result.extend(flatten(i))
return result
|
Posts: 2,128
Threads: 11
Joined: May 2017
Nov-24-2018, 09:23 PM
(This post was last modified: Nov-24-2018, 09:24 PM by DeaD_EyE.)
I made a while ago a function to flatten deep nested structures. I wrote it, but I still need 2 minutes to watch this code, to understand what I have done :-D
https://stackoverflow.com/questions/2158...1#45213701
There is still an big error inside. I do not pay attention about bytearrays.
Posts: 66
Threads: 19
Joined: Nov 2018
Thanks to both of you. I will check how do your codes sit into my program.. :)
|