How do I convert a tuple of tuples to a one-dimensional list using list comprehension?
本问题已经有最佳答案,请猛点这里访问。
我有一个元组-例如:
1 | tupleOfTuples = ((1, 2), (3, 4), (5,)) |
我想把它转换成一个平面的一维的所有元素的列表,顺序如下:
1 | [1, 2, 3, 4, 5] |
我一直试图通过列表理解来完成这项工作。但我似乎不明白。我可以通过一个for-each循环来完成它:
1 2 3 | myList = [] for tuple in tupleOfTuples: myList = myList + list(tuple) |
但我觉得必须有一种方法来理解列表。
一个简单的
1 | [*list(tuple) for tuple in tupleOfTuples] |
或
1 | [*(list(tuple)) for tuple in tupleOfTuples] |
…但那不起作用。有什么想法吗?还是我应该坚持这个循环?
它通常被称为扁平嵌套结构。
1 2 3 | >>> tupleOfTuples = ((1, 2), (3, 4), (5,)) >>> [element for tupl in tupleOfTuples for element in tupl] [1, 2, 3, 4, 5] |
为了证明效率:
1 2 3 4 5 6 7 | >>> import timeit >>> it = lambda: list(chain(*tupleOfTuples)) >>> timeit.timeit(it) 2.1475738355700913 >>> lc = lambda: [element for tupl in tupleOfTuples for element in tupl] >>> timeit.timeit(lc) 1.5745135182887857 |
ETA:请不要使用
如果没有很多元组,只需使用
1 2 3 4 5 | >>> tupleOfTuples = ((1, 2), (3, 4), (5,)) >>> sum(tupleOfTuples, ()) (1, 2, 3, 4, 5) >>> list(sum(tupleOfTuples, ())) # if you really need a list [1, 2, 3, 4, 5] |
如果你确实有很多元组,可以使用list理解或者
Python 2.6
短元组的长元组
1
2
3
4
5
6
7
8$ python2.6 -m timeit -s 'tot = ((1, 2), )*500' '[element for tupl in tot for element in tupl]'
10000 loops, best of 3: 134 usec per loop
$ python2.6 -m timeit -s 'tot = ((1, 2), )*500' 'list(sum(tot, ()))'
1000 loops, best of 3: 1.1 msec per loop
$ python2.6 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
10000 loops, best of 3: 60.1 usec per loop
$ python2.6 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain' 'list(chain(*tot))'
10000 loops, best of 3: 64.8 usec per loop长元组的短元组
1
2
3
4
5
6
7
8$ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500)' '[element for tupl in tot for element in tupl]'
10000 loops, best of 3: 65.6 usec per loop
$ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500)' 'list(sum(tot, ()))'
100000 loops, best of 3: 16.9 usec per loop
$ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
10000 loops, best of 3: 25.8 usec per loop
$ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain' 'list(chain(*tot))'
10000 loops, best of 3: 26.5 usec per loop
Python 3.1
短元组的长元组
1
2
3
4
5
6
7
8$ python3.1 -m timeit -s 'tot = ((1, 2), )*500' '[element for tupl in tot for element in tupl]'
10000 loops, best of 3: 121 usec per loop
$ python3.1 -m timeit -s 'tot = ((1, 2), )*500' 'list(sum(tot, ()))'
1000 loops, best of 3: 1.09 msec per loop
$ python3.1 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
10000 loops, best of 3: 59.5 usec per loop
$ python3.1 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain' 'list(chain(*tot))'
10000 loops, best of 3: 63.2 usec per loop长元组的短元组
1
2
3
4
5
6
7
8$ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500)' '[element for tupl in tot for element in tupl]'
10000 loops, best of 3: 66.1 usec per loop
$ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500)' 'list(sum(tot, ()))'
100000 loops, best of 3: 16.3 usec per loop
$ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
10000 loops, best of 3: 25.4 usec per loop
$ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain' 'list(chain(*tot))'
10000 loops, best of 3: 25.6 usec per loop
观察:
- 如果外部元组较短,则
sum 更快。 - 如果外元组较长,则
list(chain.from_iterable(x)) 更快。
这些答案中的大多数只适用于单一水平的压平。要获得更全面的解决方案,请尝试以下方法(http://rightfootin.blogspot.com/2006/09/more on python flatten.html):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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) |
你把这些元组链接在一起:
1 2 | from itertools import chain print list(chain(*listOfTuples)) |
如果你熟悉
我喜欢在这种情况下使用reduce(这就是reduce的用途!)
1 2 3 4 | lot = ((1, 2), (3, 4), (5,)) print list(reduce(lambda t1, t2: t1 + t2, lot)) > [1,2,3,4,5] |
对于多级可读代码:
1 2 3 4 5 | def flatten(bla): output = [] for item in bla: output += flatten(item) if hasattr (item,"__iter__") or hasattr (item,"__len__") else [item] return output |
我不能把它放在一行中(即使到目前为止,它仍然是可读的)
使用itertools.chain的另一个解决方案
1 2 3 4 | >>> tupleOfTuples = ((1, 2), (3, 4), (5,)) >>> from itertools import chain >>> [x for x in chain.from_iterable(tupleOfTuples)] [1, 2, 3, 4, 5] |