How to flatten a list to return a new list with all the elements?
Question:
I am trying to write a function called flatten_list that takes as input a list which may be nested, and returns a non-nested list with all the elements of the input list.
My code:
def flatten_list(alist):
"""
>>> flatten_list([1,2,3])
[1, 2, 3]
>>> flatten_list([1, [2,3], [4, 5], 6])
[1, 2, 3, 4, 5, 6]
"""
flat_list = []
for element in alist:
flat_list += element
return flat_list
This code works for lists with strings, but not integer values. How can I change the code so that it works for both?
thanks
Answers:
You can do it as:
a = [1, [2,3], [4, 5], 6]
def flatten(l,result = []):
if isinstance(l, list):
for i in l:
flatten(i)
else:
result.append(l)
return result
>>> print flatten(a)
[1, 2, 3, 4, 5, 6]
This will works for even deeper nesting levels:
>>> print flatten([1, [2, [3, 4]]])
[1, 2, 3, 4]
Generally, this would be done recursively, for example:
def flatten(input_, output=None):
if output is None:
output = []
if isinstance(input_, basestring):
output.append(input_)
else:
for item in input_:
try:
flatten(item, output)
except TypeError:
output.append(item)
return output
This will work with any combination of iterable containers (e.g. set
, list
, tuple
, dict
(keys only)) and contents (e.g. int
, float
, str
), using the common EAFP Python style. Note the specific exception for strings, which you probably don’t want to be unpacked!
A few examples of usage:
>>> flatten([1, [2, [3, [4, 5], 6], 7], 8])
[1, 2, 3, 4, 5, 6, 7, 8]
>>> flatten([1, "foo", ["bar", 2], 3])
[1, 'foo', 'bar', 2, 3]
>>> flatten([1, (2, 3), {4: 5}])
[1, 2, 3, 4]
>>> flatten("hello")
['hello']
And what happens with non-iterables as direct arguments:
>>> flatten(1)
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
flatten(1)
File "<pyshell#1>", line 4, in flatten
for item in input_:
TypeError: 'int' object is not iterable
using collections.Iterable
from collections import Iterable
def flatten(items):
for elem in items:
if isinstance(elem,Iterable) and not isinstance(elem,str):
for sub_elem in flatten(elem):
yield sub_elem
else:
yield elem
In [15]: print list(flatten((1, (2,3), [4, 5],{10,11,12}, 6)))
[1, 2, 3, 4, 5, 10, 11, 12, 6]
In [16]: print list(flatten((1, (2,3), (4,5,6), 6)))
[1, 2, 3, 4, 5, 6, 6]
In [17]: print list(flatten([1, "foo", ["bar", 2], 3]))
[1, 'foo', 'bar', 2, 3]
I am trying to write a function called flatten_list that takes as input a list which may be nested, and returns a non-nested list with all the elements of the input list.
My code:
def flatten_list(alist):
"""
>>> flatten_list([1,2,3])
[1, 2, 3]
>>> flatten_list([1, [2,3], [4, 5], 6])
[1, 2, 3, 4, 5, 6]
"""
flat_list = []
for element in alist:
flat_list += element
return flat_list
This code works for lists with strings, but not integer values. How can I change the code so that it works for both?
thanks
You can do it as:
a = [1, [2,3], [4, 5], 6]
def flatten(l,result = []):
if isinstance(l, list):
for i in l:
flatten(i)
else:
result.append(l)
return result
>>> print flatten(a)
[1, 2, 3, 4, 5, 6]
This will works for even deeper nesting levels:
>>> print flatten([1, [2, [3, 4]]])
[1, 2, 3, 4]
Generally, this would be done recursively, for example:
def flatten(input_, output=None):
if output is None:
output = []
if isinstance(input_, basestring):
output.append(input_)
else:
for item in input_:
try:
flatten(item, output)
except TypeError:
output.append(item)
return output
This will work with any combination of iterable containers (e.g. set
, list
, tuple
, dict
(keys only)) and contents (e.g. int
, float
, str
), using the common EAFP Python style. Note the specific exception for strings, which you probably don’t want to be unpacked!
A few examples of usage:
>>> flatten([1, [2, [3, [4, 5], 6], 7], 8])
[1, 2, 3, 4, 5, 6, 7, 8]
>>> flatten([1, "foo", ["bar", 2], 3])
[1, 'foo', 'bar', 2, 3]
>>> flatten([1, (2, 3), {4: 5}])
[1, 2, 3, 4]
>>> flatten("hello")
['hello']
And what happens with non-iterables as direct arguments:
>>> flatten(1)
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
flatten(1)
File "<pyshell#1>", line 4, in flatten
for item in input_:
TypeError: 'int' object is not iterable
using collections.Iterable
from collections import Iterable
def flatten(items):
for elem in items:
if isinstance(elem,Iterable) and not isinstance(elem,str):
for sub_elem in flatten(elem):
yield sub_elem
else:
yield elem
In [15]: print list(flatten((1, (2,3), [4, 5],{10,11,12}, 6)))
[1, 2, 3, 4, 5, 10, 11, 12, 6]
In [16]: print list(flatten((1, (2,3), (4,5,6), 6)))
[1, 2, 3, 4, 5, 6, 6]
In [17]: print list(flatten([1, "foo", ["bar", 2], 3]))
[1, 'foo', 'bar', 2, 3]