l =[[1,2,3],[4,5,6],[7],[8,9]]
reduce(lambda x, y: x.extend(y), l)
错误信息
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'
回答 0
给定一个列表列表l,
flat_list = [item for sublist in l for item in sublist]
意思是:
flat_list =[]for sublist in l:for item in sublist:
flat_list.append(item)
比到目前为止发布的快捷方式快。(l是要展平的列表。)
这是相应的功能:
flatten =lambda l:[item for sublist in l for item in sublist]
作为证据,您可以使用timeit标准库中的模块:
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99''[item for sublist in l for item in sublist]'10000 loops, best of 3:143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99''sum(l, [])'1000 loops, best of 3:969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99''reduce(lambda x,y: x+y,l)'1000 loops, best of 3:1.1 msec per loop
flat_list = [item for sublist in l for item in sublist]
which means:
flat_list = []
for sublist in l:
for item in sublist:
flat_list.append(item)
is faster than the shortcuts posted so far. (l is the list to flatten.)
Here is the corresponding function:
flatten = lambda l: [item for sublist in l for item in sublist]
As evidence, you can use the timeit module in the standard library:
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 1.1 msec per loop
Explanation: the shortcuts based on + (including the implied use in sum) are, of necessity, O(L**2) when there are L sublists — as the intermediate result list keeps getting longer, at each step a new intermediate result list object gets allocated, and all the items in the previous intermediate result must be copied over (as well as a few new ones added at the end). So, for simplicity and without actual loss of generality, say you have L sublists of I items each: the first I items are copied back and forth L-1 times, the second I items L-2 times, and so on; total number of copies is I times the sum of x for x from 1 to L excluded, i.e., I * (L**2)/2.
The list comprehension just generates one list, once, and copies each item over (from its original place of residence to the result list) also exactly once.
Note from the author: This is inefficient. But fun, because monoids are awesome. It’s not appropriate for production Python code.
>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
This just sums the elements of iterable passed in the first argument, treating second argument as the initial value of the sum (if not given, 0 is used instead and this case will give you an error).
Because you are summing nested lists, you actually get [1,3]+[2,4] as a result of sum([[1,3],[2,4]],[]), which is equal to [1,3,2,4].
Note that only works on lists of lists. For lists of lists of lists, you’ll need another solution.
>>> from matplotlib.cbook import flatten
>>> list(flatten(l))
…Unipath:
>>> from unipath.path import flatten
>>> list(flatten(l))
…Setuptools:
>>> from setuptools.namespaces import flatten
>>> list(flatten(l))
回答 6
这是适用于数字,字符串,嵌套列表和混合容器的通用方法。
码
#from typing import Iterable from collections importIterable# < py38def flatten(items):"""Yield items from any nested iterable; see Reference."""for x in items:if isinstance(x,Iterable)andnot isinstance(x,(str, bytes)):for sub_x in flatten(x):yield sub_x
else:yield x
注意事项:
在Python 3中,yield from flatten(x)可以替换for sub_x in flatten(x): yield sub_x
Here is a general approach that applies to numbers, strings, nested lists and mixed containers.
Code
#from typing import Iterable
from collections import Iterable # < py38
def flatten(items):
"""Yield items from any nested iterable; see Reference."""
for x in items:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
for sub_x in flatten(x):
yield sub_x
else:
yield x
Notes:
In Python 3, yield from flatten(x) can replace for sub_x in flatten(x): yield sub_x
from itertools import chain
from functools import reduce
from collections importIterable# or from collections.abc import Iterableimport operator
from iteration_utilities import deepflatten
def nested_list_comprehension(lsts):return[item for sublist in lsts for item in sublist]def itertools_chain_from_iterable(lsts):return list(chain.from_iterable(lsts))def pythons_sum(lsts):return sum(lsts,[])def reduce_add(lsts):return reduce(lambda x, y: x + y, lsts)def pylangs_flatten(lsts):return list(flatten(lsts))def flatten(items):"""Yield items from any nested iterable; see REF."""for x in items:if isinstance(x,Iterable)andnot isinstance(x,(str, bytes)):yieldfrom flatten(x)else:yield x
def reduce_concat(lsts):return reduce(operator.concat, lsts)def iteration_utilities_deepflatten(lsts):return list(deepflatten(lsts, depth=1))from simple_benchmark import benchmark
b = benchmark([nested_list_comprehension, itertools_chain_from_iterable, pythons_sum, reduce_add,
pylangs_flatten, reduce_concat, iteration_utilities_deepflatten],
arguments={2**i:[[0]*5]*(2**i)for i in range(1,13)},
argument_name='number of inner lists')
b.plot()
Just to add some timings (based on Nico Schlömer answer that didn’t include the function presented in this answer):
It’s a log-log plot to accommodate for the huge range of values spanned. For qualitative reasoning: Lower is better.
The results show that if the iterable contains only a few inner iterables then sum will be fastest, however for long iterables only the itertools.chain.from_iterable, iteration_utilities.deepflatten or the nested comprehension have reasonable performance with itertools.chain.from_iterable being the fastest (as already noticed by Nico Schlömer).
from itertools import chain
from functools import reduce
from collections import Iterable # or from collections.abc import Iterable
import operator
from iteration_utilities import deepflatten
def nested_list_comprehension(lsts):
return [item for sublist in lsts for item in sublist]
def itertools_chain_from_iterable(lsts):
return list(chain.from_iterable(lsts))
def pythons_sum(lsts):
return sum(lsts, [])
def reduce_add(lsts):
return reduce(lambda x, y: x + y, lsts)
def pylangs_flatten(lsts):
return list(flatten(lsts))
def flatten(items):
"""Yield items from any nested iterable; see REF."""
for x in items:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
yield from flatten(x)
else:
yield x
def reduce_concat(lsts):
return reduce(operator.concat, lsts)
def iteration_utilities_deepflatten(lsts):
return list(deepflatten(lsts, depth=1))
from simple_benchmark import benchmark
b = benchmark(
[nested_list_comprehension, itertools_chain_from_iterable, pythons_sum, reduce_add,
pylangs_flatten, reduce_concat, iteration_utilities_deepflatten],
arguments={2**i: [[0]*5]*(2**i) for i in range(1, 13)},
argument_name='number of inner lists'
)
b.plot()
1 Disclaimer: I’m the author of that library
回答 8
我收回我的声明。总和不是赢家。尽管列表较小时速度更快。但是,列表较大时,性能会大大降低。
>>> timeit.Timer('[item for sublist in l for item in sublist]','l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10000').timeit(100)2.0440959930419922
I take my statement back. sum is not the winner. Although it is faster when the list is small. But the performance degrades significantly with larger lists.
>>> timeit.Timer(
'[item for sublist in l for item in sublist]',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10000'
).timeit(100)
2.0440959930419922
The sum version is still running for more than a minute and it hasn’t done processing yet!
There seems to be a confusion with operator.add! When you add two lists together, the correct term for that is concat, not add. operator.concat is what you need to use.
If you’re thinking functional, it is as easy as this::
The reason your function didn’t work is because the extend extends an array in-place and doesn’t return it. You can still return x from lambda, using something like this:
reduce(lambda x,y: x.extend(y) or x, l)
Note: extend is more efficient than + on lists.
回答 13
def flatten(l, a):for i in l:if isinstance(i, list):
flatten(i, a)else:
a.append(i)return a
print(flatten([[[1,[1,1,[3,[4,5,]]]],2,3],[4,5],6],[]))# [1, 1, 1, 3, 4, 5, 2, 3, 4, 5, 6]
def flatten(l, a):
for i in l:
if isinstance(i, list):
flatten(i, a)
else:
a.append(i)
return a
print(flatten([[[1, [1,1, [3, [4,5,]]]], 2, 3], [4, 5],6], []))
# [1, 1, 1, 3, 4, 5, 2, 3, 4, 5, 6]
回答 14
递归版本
x =[1,2,[3,4],[5,[6,[7]]],8,9,[10]]def flatten_list(k):
result = list()for i in k:if isinstance(i,list):#The isinstance() function checks if the object (first argument) is an #instance or subclass of classinfo class (second argument)
result.extend(flatten_list(i))#Recursive callelse:
result.append(i)return result
flatten_list(x)#result = [1,2,3,4,5,6,7,8,9,10]
x = [1,2,[3,4],[5,[6,[7]]],8,9,[10]]
def flatten_list(k):
result = list()
for i in k:
if isinstance(i,list):
#The isinstance() function checks if the object (first argument) is an
#instance or subclass of classinfo class (second argument)
result.extend(flatten_list(i)) #Recursive call
else:
result.append(i)
return result
flatten_list(x)
#result = [1,2,3,4,5,6,7,8,9,10]
Average time over 1000 trials of matplotlib.cbook.flatten:2.55e-05 sec
Average time over 1000 trials of underscore._.flatten:4.63e-04 sec
(time for underscore._)/(time for matplotlib.cbook)=18.1233394636
Average time over 1000 trials of matplotlib.cbook.flatten: 2.55e-05 sec
Average time over 1000 trials of underscore._.flatten: 4.63e-04 sec
(time for underscore._)/(time for matplotlib.cbook) = 18.1233394636
回答 16
在处理基于文本的可变长度列表时,可接受的答案对我不起作用。这是对我有用的另一种方法。
l =['aaa','bb','cccccc',['xx','yyyyyyy']]
接受的答案无效:
flat_list =[item for sublist in l for item in sublist]print(flat_list)['a','a','a','b','b','c','c','c','c','c','c','xx','yyyyyyy']
新提出的解决方案,没有工作对我来说:
flat_list =[]
_ =[flat_list.extend(item)if isinstance(item, list)else flat_list.append(item)for item in l if item]print(flat_list)['aaa','bb','cccccc','xx','yyyyyyy']
The accepted answer did not work for me when dealing with text-based lists of variable lengths. Here is an alternate approach that did work for me.
l = ['aaa', 'bb', 'cccccc', ['xx', 'yyyyyyy']]
Accepted answer that did not work:
flat_list = [item for sublist in l for item in sublist]
print(flat_list)
['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'c', 'c', 'xx', 'yyyyyyy']
New proposed solution that did work for me:
flat_list = []
_ = [flat_list.extend(item) if isinstance(item, list) else flat_list.append(item) for item in l if item]
print(flat_list)
['aaa', 'bb', 'cccccc', 'xx', 'yyyyyyy']
def list_flatten(l, a=None):#check aif a isNone:#initialize with empty list
a =[]for i in l:if isinstance(i, list):
list_flatten(i, a)else:
a.append(i)return a
An bad feature of Anil’s function above is that it requires the user to always manually specify the second argument to be an empty list []. This should instead be a default. Due to the way Python objects work, these should be set inside the function, not in the arguments.
Here’s a working function:
def list_flatten(l, a=None):
#check a
if a is None:
#initialize with empty list
a = []
for i in l:
if isinstance(i, list):
list_flatten(i, a)
else:
a.append(i)
return a
Testing:
In [2]: lst = [1, 2, [3], [[4]],[5,[6]]]
In [3]: lst
Out[3]: [1, 2, [3], [[4]], [5, [6]]]
In [11]: list_flatten(lst)
Out[11]: [1, 2, 3, 4, 5, 6]
回答 18
以下对我来说似乎最简单:
>>>import numpy as np
>>> l =[[1,2,3],[4,5,6],[7],[8,9]]>>>print(np.concatenate(l))[123456789]
import numpy
l =[[1,2,3],[4,5,6],[7],[8,9]]*99%timeit numpy.concatenate(l).ravel().tolist()1000 loops, best of 3:313µs per loop
%timeit numpy.concatenate(l).tolist()1000 loops, best of 3:312µs per loop
%timeit [item for sublist in l for item in sublist]1000 loops, best of 3:31.5µs per loop
If you are willing to give up a tiny amount of speed for a cleaner look, then you could use numpy.concatenate().tolist() or numpy.concatenate().ravel().tolist():
import numpy
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]] * 99
%timeit numpy.concatenate(l).ravel().tolist()
1000 loops, best of 3: 313 µs per loop
%timeit numpy.concatenate(l).tolist()
1000 loops, best of 3: 312 µs per loop
%timeit [item for sublist in l for item in sublist]
1000 loops, best of 3: 31.5 µs per loop
>>>from collections importIterable>>>from six import string_types
>>>def flatten(obj):...for i in obj:...if isinstance(i,Iterable)andnot isinstance(i, string_types):...yieldfrom flatten(i)...else:...yield i
>>> list(flatten(obj))[1,2,3,4,5,6,'abc',7,8,9,10]
Note: Below applies to Python 3.3+ because it uses yield_from. six is also a third-party package, though it is stable. Alternately, you could use sys.version.
In the case of obj = [[1, 2,], [3, 4], [5, 6]], all of the solutions here are good, including list comprehension and itertools.chain.from_iterable.
However, consider this slightly more complex case:
One element, 6, is just a scalar; it’s not iterable, so the above routes will fail here.
One element, 'abc', is technically iterable (all strs are). However, reading between the lines a bit, you don’t want to treat it as such–you want to treat it as a single element.
The final element, [8, [9, 10]] is itself a nested iterable. Basic list comprehension and chain.from_iterable only extract “1 level down.”
You can remedy this as follows:
>>> from collections import Iterable
>>> from six import string_types
>>> def flatten(obj):
... for i in obj:
... if isinstance(i, Iterable) and not isinstance(i, string_types):
... yield from flatten(i)
... else:
... yield i
>>> list(flatten(obj))
[1, 2, 3, 4, 5, 6, 'abc', 7, 8, 9, 10]
Here, you check that the sub-element (1) is iterable with Iterable, an ABC from itertools, but also want to ensure that (2) the element is not “string-like.”
flat_list = []
for i in list_of_list:
flat_list+=i
This Code also works fine as it just extend the list all the way. Although it is much similar but only have one for loop. So It have less complexity than adding 2 for loops.
回答 27
from nltk import flatten
l =[[1,2,3],[4,5,6],[7],[8,9]]
flatten(l)
a =[[1,2],[[[[3,4,5],6]]],7,[8,[9,[10,11],12,[13,14,[15,[[16,17],18]]]]]]
flist =[]def make_list_flat (l):
flist.extend ([l])if(type (l)isnot list)else[make_list_flat (e)for e in l]
make_list_flat(a)print(flist)
This may not be the most efficient way but I thought to put a one-liner (actually a two-liner). Both versions will work on arbitrary hierarchy nested lists, and exploits language features (Python3.5) and recursion.
def make_list_flat (l):
flist = []
flist.extend ([l]) if (type (l) is not list) else [flist.extend (make_list_flat (e)) for e in l]
return flist
a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = make_list_flat(a)
print (flist)
This works in a depth first manner. The recursion goes down until it finds a non-list element, then extends the local variable flist and then rolls back it to the parent. Whenever flist is returned, it is extended to the parent’s flist in the list comprehension. Therefore, at the root, a flat list is returned.
The above one creates several local lists and returns them which are used to extend the parent’s list. I think the way around for this may be creating a gloabl flist, like below.
a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = []
def make_list_flat (l):
flist.extend ([l]) if (type (l) is not list) else [make_list_flat (e) for e in l]
make_list_flat(a)
print (flist)
Although I am not sure at this time about the efficiency.
回答 29
适用于整数的异质和均质列表的另一种异常方法:
from typing importListdef flatten(l: list)->List[int]:"""Flatten an arbitrary deep nested list of lists of integers.
Examples:
>>> flatten([1, 2, [1, [10]]])
[1, 2, 1, 10]
Args:
l: Union[l, Union[int, List[int]]
Returns:
Flatted list of integer
"""return[int(i.strip('[ ]'))for i in str(l).split(',')]
Another unusual approach that works for hetero- and homogeneous lists of integers:
from typing import List
def flatten(l: list) -> List[int]:
"""Flatten an arbitrary deep nested list of lists of integers.
Examples:
>>> flatten([1, 2, [1, [10]]])
[1, 2, 1, 10]
Args:
l: Union[l, Union[int, List[int]]
Returns:
Flatted list of integer
"""
return [int(i.strip('[ ]')) for i in str(l).split(',')]