python列表parsing; 压缩列表的列表?
家伙。 我试图find一个问题的最优雅的解决scheme,并想知道是否有什么内置的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有类似的东西吗? 有没有一个整洁的方式来映射一个函数的列表,并平坦的结果?
我试图解决的实际问题是这样的; 从目录列表开始,find所有的子目录。 所以;
import os dirs = ["c:\\usr", "c:\\temp"] subs = [os.listdir(d) for d in dirs] print subs
currentliy给了我一个清单,但我真的想要一个清单。
您可以在单个列表理解中嵌套迭代:
[filename for path in dirs for filename in os.listdir(path)]
>>> listOfLists = [[1, 2],[3, 4, 5], [6]] >>> reduce(list.__add__, listOfLists) [1, 2, 3, 4, 5, 6]
我猜itertools解决scheme比这更有效率,但是这感觉非常pythonic,并避免必须导入库只是为了一个单一的列表操作。
你可以在itertools的食谱中find一个很好的答案:
def flatten(listOfLists): return list(chain.from_iterable(listOfLists))
(注意:需要Python 2.6+)
你可以做简单的事情:
subs = [] for d in dirs: subs.extend(os.listdir(d))
这个问题提出了flatmap
。 提出了一些实现,但是可能不需要创build中间列表。 这是一个基于迭代器的实现。
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
。
您可以使用普通的加法运算符连接列表:
>>> [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将不必要的构build和垃圾收集大量的这个解决scheme的小列表。 所以,可以说的最好的事情是,如果你习惯于函数式编程,它是非常简单和简洁的:-)
import itertools x=[['b11','b12'],['b21','b22'],['b31']] y=list(itertools.chain(*x)) print y
itertools将从python2.3和更高版本工作
subs = [] map(subs.extend, (os.listdir(d) for d in dirs))
(但ant的答案是更好的,他+1)
你可以尝试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()
。
Google给我带来了下一个解
def flatten(l): if isinstance(l,list): return sum(map(flatten,l)) else: return l
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
If listA=[list1,list2,list3] flattened_list=reduce(lambda x,y:x+y,listA)
这会做。
你可以使用pyxtension :
from pyxtension.streams import stream stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(7)