如何从列表推导而不是嵌套列表获得平坦的结果?
- 2025-01-03 08:41:00
- admin 原创
- 96
问题描述:
我有一个列表A
,以及一个f
接受 的项目A
并返回列表的函数。我可以使用列表推导将 中的所有内容转换A
为[f(a) for a in A]
,但这会返回一个列表列表。假设我的输入是[a1,a2,a3]
,结果为[[b11,b12],[b21,b22],[b31,b32]]
。
我怎样才能获得扁平列表[b11,b12,b21,b22,b31,b32]
?换句话说,在 Python 中,我怎样才能获得flatmap
函数式编程语言或SelectMany
.NET 中传统上所称的内容?
(在实际代码中,A
是目录列表,f
是os.listdir
。我想建立一个平面的子目录列表。)
另请参阅:如何从列表列表中创建平面列表?以解决在创建列表列表后将其平面化的更普遍问题。
解决方案 1:
你可以在单个列表推导中进行嵌套迭代:
[filename for path in dirs for filename in os.listdir(path)]
其至少在功能上等同于:
filenames = []
for path in dirs:
for filename in os.listdir(path):
filenames.append(filename)
解决方案 2:
>>> from functools import reduce # not needed on Python 2
>>> list_of_lists = [[1, 2],[3, 4, 5], [6]]
>>> reduce(list.__add__, list_of_lists)
[1, 2, 3, 4, 5, 6]
该itertools
解决方案更有效,但感觉非常 Pythonic。
解决方案 3:
itertools
您可以在食谱中找到很好的答案:
import itertools
def flatten(list_of_lists):
return list(itertools.chain.from_iterable(list_of_lists))
解决方案 4:
提出的问题flatmap
。提出了一些实现,但它们可能不需要创建中间列表。这是一个基于迭代器的实现。
def flatmap(func, *iterable):
return itertools.chain.from_iterable(map(func, *iterable))
In [148]: list(flatmap(os.listdir, ['c:/mfg','c:/Intel']))
Out[148]: ['SPEC.pdf', 'W7ADD64EN006.cdr', 'W7ADD64EN006.pdf', 'ExtremeGraphics', 'Logs']
在 Python 2.x 中,使用itertools.map
代替map
。
解决方案 5:
你可以直接这样做:
subs = []
for d in dirs:
subs.extend(os.listdir(d))
解决方案 6:
您可以使用常规加法运算符连接列表:
>>> [1, 2] + [3, 4]
[1, 2, 3, 4]
内置函数sum
将按顺序添加数字,并可以选择从特定值开始:
>>> sum(xrange(10), 100)
145
结合以上内容来展平列表列表:
>>> sum([[1, 2], [3, 4]], [])
[1, 2, 3, 4]
您现在可以定义您的flatmap
:
>>> def flatmap(f, seq):
... return sum([f(s) for s in seq], [])
...
>>> flatmap(range, [1,2,3])
[0, 0, 1, 0, 1, 2]
编辑:我刚刚在评论中看到了对另一个答案的批评,我猜 Python 会用这个解决方案不必要地构建和垃圾收集大量较小的列表,这是正确的。所以可以说的最好的事情是,如果你习惯了函数式编程,它非常简单和简洁 :-)
解决方案 7:
subs = []
map(subs.extend, (os.listdir(d) for d in dirs))
(但 Ants 的答案更好;对他来说 +1)
解决方案 8:
import itertools
x=[['b11','b12'],['b21','b22'],['b31']]
y=list(itertools.chain(*x))
print y
itertools 适用于 python2.3 及更高版本
解决方案 9:
您可以尝试itertools.chain()
这样做:
import itertools
import os
dirs = ["c:\/usr", "c:\\temp"]
subs = list(itertools.chain(*[os.listdir(d) for d in dirs]))
print subs
itertools.chain()
返回一个迭代器,因此传递给list()
。
解决方案 10:
这是最简单的方法:
def flatMap(array):
return reduce(lambda a,b: a+b, array)
'a+b' 表示两个列表的连接
解决方案 11:
您可以使用pyxtension:
from pyxtension.streams import stream
stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(7)
解决方案 12:
谷歌给我带来了下一个解决方案:
def flatten(l):
if isinstance(l,list):
return sum(map(flatten,l))
else:
return l
解决方案 13:
我一直在寻找flatmap
并首先找到了这个问题。flatmap
基本上是对原始问题要求的概括。如果您正在寻找一种简洁的方式来定义flatmap
可求和的集合(例如列表),您可以使用
sum(map(f,xs),[])
它只比写作长一点
flatmap(f,xs)
但一开始可能不太清楚。
最明智的解决方案是将其作为flatmap
编程语言中的一个基本函数,但只要它不是,您仍然可以使用更好或更具体的名称来定义它:
# `function` must turn the element type of `xs` into a summable type.
# `function` must be defined for arguments constructed without parameters.
def aggregate(function, xs):
return sum( map(function, xs), type(function( type(xs)() ))() )
# or only for lists
aggregate_list = lambda f,xs: sum(map(f,xs),[])
不幸的是,字符串不可求和,因此它不适用于它们。
你可以这样做
assert( aggregate_list( lambda x: x * [x], [2,3,4] ) == [2,2,3,3,3,4,4,4,4] )
但你不能这样做
def get_index_in_alphabet(character):
return (ord(character) & ~0x20) - ord('A')
assert(aggregate( lambda x: get_index_in_alphabet(x) * x, "abcd") == "bccddd")
对于字符串,您需要使用
aggregate_string = lambda f,s: "".join(map(f,s)) # looks almost like sum(map(f,s),"")
assert( aggregate_string( lambda x: get_index_in_alphabet(x) * x, "abcd" ) == "bccddd" )
这显然很乱,不同类型的函数需要不同的函数名,甚至语法。希望 Python 的类型系统将来能够得到改进。
解决方案 14:
您还可以使用该flatten
函数numpy
:
import numpy as np
matrix = [[i+k for i in range(10)] for k in range(10)]
matrix_flat = np.array(arr).flatten()
numpy 文档flatten
解决方案 15:
为什么不能将flatten
函数flat_map
应用于任何使用生成器的可迭代对象?
def flatten(iters):
for it in iters:
for elem in it:
yield elem
def flat_map(fn, it):
return flatten(map(fn, it))
使用方法非常简单:
for e in flat_map(range, [1, 2, 3]):
print(e, end=" ")
# Output: 0 0 1 0 1 2
作为一个有趣的琐事,你flatten
也可以用递归的方式编写。分析留给感兴趣的读者吧!
def flatten(it):
try:
yield from next(it)
yield from flatten(it)
except StopIteration:
pass
解决方案 16:
If listA=[list1,list2,list3]
flattened_list=reduce(lambda x,y:x+y,listA)
这样就可以了。