连接在Python列表中的列表

在python中join一个列表列表(或迭代器)的简短语法?

例如,我有一个列表如下,我想迭代a,b和c。

x = [["a","b"], ["c"]] 

我能拿出的最好的如下。

 result = [] [ result.extend(el) for el in x] for el in result: print el 
 import itertools a = [["a","b"], ["c"]] print list(itertools.chain.from_iterable(a)) 

如果你只深入一层,嵌套的理解也将起作用:

 >>> x = [["a","b"], ["c"]] >>> [inner ... for outer in x ... for inner in outer] ['a', 'b', 'c'] 

在一条线上,这成为:

 >>> [j for i in x for j in i] ['a', 'b', 'c'] 
 x = [["a","b"], ["c"]] result = sum(x, []) 

这被称为扁平化,并有很多实现在那里:

  • 更多关于python flatten
  • Python技巧
  • 在Python中展平列表

这个怎么样,虽然它只能用于1层深的嵌套:

 >>> x = [["a","b"], ["c"]] >>> for el in sum(x, []): ... print el ... a b c 

从这些链接中,显然是最完整,最快捷,最优雅的等等实现如下:

 def flatten(l, ltypes=(list, tuple)): ltype = type(l) l = list(l) i = 0 while i < len(l): while isinstance(l[i], ltypes): if not l[i]: l.pop(i) i -= 1 break else: l[i:i + 1] = l[i] i += 1 return ltype(l) 
 l = [] map(l.extend, list_of_lists) 

最短!

这对无限嵌套的元素recursion地工作:

 def iterFlatten(root): if isinstance(root, (list, tuple)): for element in root: for e in iterFlatten(element): yield e else: yield root 

结果:

 >>> b = [[“a”,(“b”,“c”)],“d”]
 >>> list(iterFlatten(b))
 ['A B C D']

晚了,但是…

我是python新手,来自lisp背景。 这就是我想出的(查看lulz的var名称):

 def flatten(lst): if lst: car,*cdr=lst if isinstance(car,(list,tuple)): if cdr: return flatten(car) + flatten(cdr) return flatten(car) if cdr: return [car] + flatten(cdr) return [car] 

似乎工作。 testing:

 flatten((1,2,3,(4,5,6,(7,8,(((1,2))))))) 

收益:

 [1, 2, 3, 4, 5, 6, 7, 8, 1, 2] 

你所描述的是列表弄平 ,用这些新的知识,你可以在Google上find很多解决scheme(没有内置的扁平化方法)。 这是其中之一,从http://www.daniel-lemire.com/blog/archives/2006/05/10/flattening-lists-in-python/

 def flatten(x): flat = True ans = [] for i in x: if ( i.__class__ is list): ans = flatten(i) else: ans.append(i) return ans 

性能比较:

 import itertools import timeit big_list = [[0]*1000 for i in range(1000)] timeit.repeat(lambda: list(itertools.chain.from_iterable(big_list)), number=100) timeit.repeat(lambda: list(itertools.chain(*big_list)), number=100) timeit.repeat(lambda: (lambda b: map(b.extend, big_list))([]), number=100) timeit.repeat(lambda: [el for list_ in big_list for el in list_], number=100) [100*x for x in timeit.repeat(lambda: sum(big_list, []), number=1)] 

生产:

 >>> import itertools >>> import timeit >>> big_list = [[0]*1000 for i in range(1000)] >>> timeit.repeat(lambda: list(itertools.chain.from_iterable(big_list)), number=100) [3.016212113769325, 3.0148865239060227, 3.0126415732791028] >>> timeit.repeat(lambda: list(itertools.chain(*big_list)), number=100) [3.019953987082083, 3.528754223385439, 3.02181439266457] >>> timeit.repeat(lambda: (lambda b: map(b.extend, big_list))([]), number=100) [1.812084445152557, 1.7702404451095965, 1.7722977998725362] >>> timeit.repeat(lambda: [el for list_ in big_list for el in list_], number=100) [5.409658160700605, 5.477502077679354, 5.444318360412744] >>> [100*x for x in timeit.repeat(lambda: sum(big_list, []), number=1)] [399.27587954973444, 400.9240571138051, 403.7521153804846] 

这是在Windows XP 32位上的Python 2.7.1,但是上面的注释中的from_iterablefrom_iterable得到的速度比map+extend快,所以它是相当平台和input依赖的。

远离sum(big_list, [])

总是减less(被弃用到functools):

 >>> x = [ [ 'a', 'b'], ['c'] ] >>> for el in reduce(lambda a,b: a+b, x, []): ... print el ... __main__:1: DeprecationWarning: reduce() not supported in 3.x; use functools.reduce() a b c >>> import functools >>> for el in functools.reduce(lambda a,b: a+b, x, []): ... print el ... a b c >>> 

不幸的是,列表连接的加号运算符不能用作函数 – 或者幸运的是,如果您希望lambdaexpression式更难以提高可见性。

或者recursion操作:

 def flatten(input): ret = [] if not isinstance(input, (list, tuple)): return [input] for i in input: if isinstance(i, (list, tuple)): ret.extend(flatten(i)) else: ret.append(i) return ret 

可悲的是,Python没有一个简单的方法来扁平化列表。 尝试这个:

 def flatten(some_list): for element in some_list: if type(element) in (tuple, list): for item in flatten(element): yield item else: yield element 

这将recursion地压扁一个列表; 你可以这样做

 result = [] [ result.extend(el) for el in x] for el in flatten(result): print el 

当我不得不创build一个包含数组元素和数量的字典时,我遇到了类似的问题。 答案是相关的,因为我扁平列表,得到我需要的元素,然后做一个组和计数。 我使用Python的映射函数来产生一个元素的元组,它是数组和数组。 请注意,groupby将数组元素本身作为keyfunc。 作为一个相对较新的Python编码器,我觉得它更容易理解,同时也是Pythonic。

在讨论代码之前,这里是我不得不首先弄平的数据样本:

 { "_id" : ObjectId("4fe3a90783157d765d000011"), "status" : [ "opencalais" ], "content_length" : 688, "open_calais_extract" : { "entities" : [ {"type" :"Person","name" : "Iman Samdura","rel_score" : 0.223 }, {"type" : "Company", "name" : "Associated Press", "rel_score" : 0.321 }, {"type" : "Country", "name" : "Indonesia", "rel_score" : 0.321 }, ... ]}, "title" : "Indonesia Police Arrest Bali Bomb Planner", "time" : "06:42 ET", "filename" : "021121bn.01", "month" : "November", "utctime" : 1037836800, "date" : "November 21, 2002", "news_type" : "bn", "day" : "21" } 

这是来自Mongo的查询结果。 下面的代码将这些列表集合在一起。

 def flatten_list(items): return sorted([entity['name'] for entity in [entities for sublist in [item['open_calais_extract']['entities'] for item in items] for entities in sublist]) 

首先,我将提取所有的“实体”集合,然后为每个实体集合迭代字典并提取名称属性。

对于单层拼合,如果你关心速度,那么在我尝试的所有条件下,这比以前的任何答案都快。 (也就是说,如果你需要结果作为一个列表,如果你只需要通过它即时迭代,那么链例子可能会更好)。它通过预先分配最终大小的列表并复制零件通过切片(这是比任何迭代器方法更低级的块拷贝):

 def join(a): """Joins a sequence of sequences into a single sequence. (One-level flattening.) Eg, join([(1,2,3), [4, 5], [6, (7, 8, 9), 10]]) = [1,2,3,4,5,6,(7,8,9),10] This is very efficient, especially when the subsequences are long. """ n = sum([len(b) for b in a]) l = [None]*n i = 0 for b in a: j = i+len(b) l[i:j] = b i = j return l 

sorting时间列表与评论:

 [(0.5391559600830078, 'flatten4b'), # join() above. (0.5400412082672119, 'flatten4c'), # Same, with sum(len(b) for b in a) (0.5419249534606934, 'flatten4a'), # Similar, using zip() (0.7351131439208984, 'flatten1b'), # list(itertools.chain.from_iterable(a)) (0.7472689151763916, 'flatten1'), # list(itertools.chain(*a)) (1.5468521118164062, 'flatten3'), # [i for j in a for i in j] (26.696547985076904, 'flatten2')] # sum(a, []) 

如果你需要一个列表,而不是一个生成器,使用list():

 from itertools import chain x = [["a","b"], ["c"]] y = list(chain(x))