Python 3 replacement for deprecated compiler.ast flatten function
Your stated function takes a nested list and flattens that into a new list.
To flatten an arbitrarily nested list into a new list, this works on Python 3 as you expect:
import collections
def flatten(x):
result = []
for el in x:
if isinstance(x, collections.Iterable) and not isinstance(el, str):
result.extend(flatten(el))
else:
result.append(el)
return result
print(flatten(["junk",["nested stuff"],[],[[]]]))
Prints:
['junk', 'nested stuff']
If you want a generator that does the same thing:
def flat_gen(x):
def iselement(e):
return not(isinstance(e, collections.Iterable) and not isinstance(e, str))
for el in x:
if iselement(el):
yield el
else:
for sub in flat_gen(el): yield sub
print(list(flat_gen(["junk",["nested stuff"],[],[[[],['deep']]]])))
# ['junk', 'nested stuff', 'deep']
For Python 3.3 and later, use yield from instead of the loop:
def flat_gen(x):
def iselement(e):
return not(isinstance(e, collections.Iterable) and not isinstance(e, str))
for el in x:
if iselement(el):
yield el
else:
yield from flat_gen(el)
Access all elements of nested lists
There are two short similar ways to do it:
import itertools
# with unpacking
list(itertools.chain(*outer))
# without unpacking
list(itertools.chain.from_iterable(outer))
Flattening a list which consist of integer and list
You can recursively flatten the data like this
>>> def rec(current_item):
... if type(current_item) == list:
... for items in current_item:
... for item in rec(items):
... yield item
... elif type(current_item) == int:
... yield current_item
and then sort it like this
>>> sorted(rec([1, [3, 6], 9, [2, [1, 3]], [4, [1], 5], [6], 1, [[2]]]))
[1, 1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 9]
Flatten an irregular (arbitrarily nested) list of lists
Using generator functions can make your example easier to read and improve performance.
Python 2
Using the Iterable
ABC added in 2.6:
from collections import Iterable
def flatten(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, basestring):
for item in flatten(x):
yield item
else:
yield x
Python 3
In Python 3, basestring
is no more, but the tuple (str, bytes)
gives the same effect. Also, the yield from
operator returns an item from a generator one at a time.
from collections.abc import Iterable
def flatten(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
yield from flatten(x)
else:
yield x
Flattened out a mixed type of list
>>> final = []
>>> a = [('1CFV',), 'NONRBP', [0.00325071141379, 0.278046326931, 0.291350892759]]
>>> for i in a:
... if hasattr(i, '__iter__'):
... for j in i:
... final.append(j)
... else:
... final.append(i)
...
>>> print final
['1CFV', 'NONRBP', 0.00325071141379, 0.27804632693100001, 0.291350892759]
Flatten a list of strings and lists of strings and lists in Python
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.)
Writing a list comprehension to flatten a nested list
You need to put your instance test in a loop, so you can extract the elements from a nested list:
[num for item in nested for num in (item if isinstance(item, list) else (item,))]
Demo:
>>> nested = nested = [[1, 2, 3], [4, 5, 6], [7, 8], [9], 10, 11]
>>> [num for item in nested for num in (item if isinstance(item, list) else (item,))]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
It helps if you first express this as a set of for
loops; your attempt essentially did this:
for item in nested:
_element = num if isinstance(item, list) for num in item else item
result.append(_element)
which is not really valid Python.
My list comprehension above instead does this:
for item in nested:
_iterable = item if isinstance(item, list) else (item,)
for num in _iterable:
_element = num
result.append(_element)
Flatten inner list without changing outer list in python
How about:
>>> s = [["a.b.c", "d", 1], ["e.f.g", "h", 2]]
>>> [k[0].split('.') + k[1:] for k in s]
[['a', 'b', 'c', 'd', 1], ['e', 'f', 'g', 'h', 2]]
This takes the list that split
returns after acting on the first element and adds it to a list consisting of the rest of them.
Related Topics
How to Set Selenium Webdriver from Headless Mode to Normal Mode Within the Same Session
How to Create a Slug in Django
Pandas Selecting by Label Sometimes Return Series, Sometimes Returns Dataframe
Tab Completion in Python's Raw_Input()
Cannot Display an Image in Tkinter
MySQL "Incorrect String Value" Error When Save Unicode String in Django
String Comparison Doesn't Seem to Work for Lines Read from a File
Selenium - Chromedriver Executable Needs to Be in Path
Python Daemon and Systemd Service
Assigning String with Boolean Expression
Removing Horizontal Lines in Image (Opencv, Python, Matplotlib)
Why Does Appending to One List Also Append to All Other Lists in My List of Lists
Embedding Ipython Qt Console in a Pyqt Application
If Two Variables Point to the Same Object, Why Doesn't Reassigning One Variable Affect the Other