人。我正试图找到一个问题最优雅的解决方案,并想知道python是否内置了我正在尝试做的事情。
我正在做的是这个。我有一个列表A
,我有一个函数f
,它接受一个项目并返回一个列表。我可以使用列表推导来转换A
中的所有内容,如此;
[f(a) for a in A]
但是这会返回一个列表列表;
[a1,a2,a3] => [[b11,b12],[b21,b22],[b31,b32]]
我真正想要的是获得扁平化列表;
[b11,b12,b21,b22,b31,b32]
现在,其他语言拥有它;它在函数式编程语言中传统上称为flatmap
,而.Net称之为SelectMany
。 python有类似的东西吗?是否有一种巧妙的方法可以在列表上映射函数并展平结果?
我想解决的实际问题是这个;从目录列表开始,找到所有子目录。所以;
import os
dirs = ["c:\\usr", "c:\\temp"]
subs = [os.listdir(d) for d in dirs]
print subs
currentliy给了我一个列表列表,但我真的想要一个列表。
答案 0 :(得分:90)
您可以在单个列表解析中嵌套迭代:
[filename for path in dirs for filename in os.listdir(path)]
答案 1 :(得分:61)
>>> listOfLists = [[1, 2],[3, 4, 5], [6]]
>>> reduce(list.__add__, listOfLists)
[1, 2, 3, 4, 5, 6]
我猜测itertools解决方案比这更有效,但这感觉非常pythonic并且避免了为了单个列表操作而必须导入库。
答案 2 :(得分:47)
def flatten(listOfLists):
return list(chain.from_iterable(listOfLists))
(注意:需要Python 2.6 +)
答案 3 :(得分:21)
提出的问题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
。
答案 4 :(得分:15)
你可以直截了当地说:
subs = []
for d in dirs:
subs.extend(os.listdir(d))
答案 5 :(得分:10)
您可以使用普通加法运算符连接列表:
>>> [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]
编辑:我刚刚在another answer的评论中看到了批评,我认为Python将不必要地构建并使用此解决方案垃圾收集大量较小的列表是正确的。所以关于它的最好的事情是,如果你习惯于函数式编程,那么它非常简单和简洁: - )
答案 6 :(得分:10)
import itertools
x=[['b11','b12'],['b21','b22'],['b31']]
y=list(itertools.chain(*x))
print y
itertools将从python2.3及更高版本
开始工作答案 7 :(得分:7)
subs = []
map(subs.extend, (os.listdir(d) for d in dirs))
(但蚂蚁的答案更好; +1给他)
答案 8 :(得分:3)
您可以尝试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()
。
答案 9 :(得分:3)
def flatten(l):
if isinstance(l,list):
return sum(map(flatten,l))
else:
return l
答案 10 :(得分:2)
您可以使用pyxtension:
from pyxtension.streams import stream
stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(7)
答案 11 :(得分:2)
这是最简单的方法:
def flatMap(array):
return reduce(lambda a,b: a+b, array)
'a+b' 表示两个列表的连接
答案 12 :(得分:1)
def flat_list(arr):
send_back = []
for i in arr:
if type(i) == list:
send_back += flat_list(i)
else:
send_back.append(i)
return send_back
答案 13 :(得分:0)
commit
这样做。