Similar questions have been asked before, but the solutions to those don't work for my use case (e.g., Making a flat list out of list of lists in Python and Flattening a shallow list in Python. I have is a list of strings and lists, where embedded list can also contain strings and lists. I want to turn this into a simple list of strings without splitting strings into list of characters.
import itertools
list_of_menuitems = ['image10', ['image00', 'image01'], ['image02', ['image03', 'image04']]]
chain = itertools.chain(*list_of_menuitems)
Resulting list:
['i', 'm', 'a', 'g', 'e', '1', '0', 'image00', 'image01', 'image02', ['image03', 'image04']]
Expected result:
['image10', 'image00', 'image01', 'image02', 'image03', 'image04']
What's the best (Pythonic) way to do this?
Flatten List using the reduce() Function of functools Module. The first argument to the reduce() function is a function itself with two arguments, and the second argument is a list. Argument function is applied cumulatively to elements in the list.
Flattening a list of lists is a process of transforming a two-Dimensional list into a One-Dimensional list by un-nesting every list element kept in the list of lists, that is, transforming [[9, 8, 7], [6, 5, 4], [3, 2, 1]] to [9, 8, 7, 6, 5, 4, 3, 2, 1].
To flatten a nested list we can use the for loop or the While loop or recursion or the deepflatten() Method. Other techniques include importing numerous external Python libraries and using their built-in functions.
The oft-repeated flatten
function can be applied to this circumstance with a simple modification.
from collections import Iterable
def flatten(coll):
for i in coll:
if isinstance(i, Iterable) and not isinstance(i, basestring):
for subc in flatten(i):
yield subc
else:
yield i
basestring
will make sure that both str
and unicode
objects are not split.
There are also versions which count on i
not having the __iter__
attribute. I don't know about all that, because I think that str
now has that attribute. But, it's worth mentioning.
(Please upvote the linked answer.)
Using recursion.
def flatten(A):
rt = []
for i in A:
if isinstance(i,list): rt.extend(flatten(i))
else: rt.append(i)
return rt
Test:
>>> list_of_menuitems = ['image10', ['image00', 'image01'], ['image02', ['image0
3', 'image04']]]
>>> flattern(list_of_menuitems)
['image10', 'image00', 'image01', 'image02', 'image03', 'image04']
The following works for strings (and would be easily adapted to other types):
def flatten_to_strings(listOfLists):
"""Flatten a list of (lists of (lists of strings)) for any level
of nesting"""
result = []
for i in listOfLists:
# Only append if i is a basestring (superclass of string)
if isinstance(i, basestring):
result.append(i)
# Otherwise call this function recursively
else:
result.extend(flatten_to_strings(i))
return result
flatten_to_strings(list_of_menuitems)
Out[2]: ['image10', 'image00', 'image01', 'image02', 'image03', 'image04']
In one specialized case when none of the list items contains one of the following delimiters []'
, you can use the following hack. I have not profiled it, but it looks obvious that, this would have a better performance than the obvious and cleaner recursive solution.
>>> str(list_of_menuitems).translate(None,"[]'").split(',')
['image10', ' image00', ' image01', ' image02', ' image03', ' image04']
I agree, this is a dirty hack, but does the JOB, without much effort.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With