Python 3 Replacement for Deprecated Compiler.Ast Flatten Function

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



Leave a reply



Submit