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)