具有可变数量元素的附加解包概括(PEP 448)
Additional Unpacking Generalizations (PEP 448) with variable number of elements
接受 PEP 448
在 Python 3.5
.
例如:
>>> l1 = [1, 2, 3]
>>> l2 = [4, 5, 6]
# unpack both iterables in a list literal
>>> joinedList = [*l1, *l2]
>>> print(joinedList)
[1, 2, 3, 4, 5, 6]
问题:有没有办法对列表的列表做类似的事情?
此代码无效:
SyntaxError: iterable unpacking cannot be used in comprehension
# List of variable size
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = [*l for l in list_of_lists]
当然,您可以执行以下操作,但看起来不太优雅且效率不高:
# List of variable size
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = list()
for l in list_of_lists:
joined_list += l
老派怎么样:sum()
代码:
joined_list = sum(list_of_lists, [])
测试代码:
# List of variable size
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = sum(list_of_lists, [])
print(joined_list)
结果:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
我不鼓励在这里使用 sum
,因为它是 Schlemiel the Painter's algorithm 的一种形式。 sum
实际上用 str
禁止它;他们并没有尝试阻止所有序列使用以避免放慢速度 sum
试图阻止每一次滥用,但这仍然是一个坏主意。
问题在于,这意味着您每次构建逐渐变大的临时 list
s,通过复制 所有内容 构建下一个临时文件后丢弃最后一个临时文件到目前为止,我一遍又一遍地看到新东西。如果第一个列表中有一百万个项目,并且您还有十个 list
可以连接到它上面,那么您将复制至少一千万个元素(即使其他十个 list
是空的).您的原始代码实际上更好,因为使用 +=
运算符执行就地扩展,在 O(n)
中保持最坏情况的性能(对于所有 list
中的 n
元素s) 范围,而不是 O(n*m)
(对于 m
list
s 中的 n
个元素)。
它也有只对一种一致的类型起作用的问题;如果一些输入是 list
s,一些是 tuple
s 和一些生成器,sum
将不起作用(因为 list.__add__
不会接受非 list
另一边的操作数)。
所以不要那样做。这是 what itertools.chain
and it's alternate constructor, itertools.chain.from_iterable
were made for:
from itertools import chain
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = list(chain.from_iterable(list_of_lists))
它是有保证的 O(n)
,可以与你向它抛出的任何迭代一起工作,等等。
是的,很明显,如果你只得到三个 list
的三个元素,这并不重要。但是,如果输入可迭代对象的大小或可迭代对象的数量任意大,或者类型不一致,chain
会起作用,sum
不会。
接受 PEP 448
在 Python 3.5
.
例如:
>>> l1 = [1, 2, 3]
>>> l2 = [4, 5, 6]
# unpack both iterables in a list literal
>>> joinedList = [*l1, *l2]
>>> print(joinedList)
[1, 2, 3, 4, 5, 6]
问题:有没有办法对列表的列表做类似的事情?
此代码无效:
SyntaxError: iterable unpacking cannot be used in comprehension
# List of variable size
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = [*l for l in list_of_lists]
当然,您可以执行以下操作,但看起来不太优雅且效率不高:
# List of variable size
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = list()
for l in list_of_lists:
joined_list += l
老派怎么样:sum()
代码:
joined_list = sum(list_of_lists, [])
测试代码:
# List of variable size
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = sum(list_of_lists, [])
print(joined_list)
结果:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
我不鼓励在这里使用 sum
,因为它是 Schlemiel the Painter's algorithm 的一种形式。 sum
实际上用 str
禁止它;他们并没有尝试阻止所有序列使用以避免放慢速度 sum
试图阻止每一次滥用,但这仍然是一个坏主意。
问题在于,这意味着您每次构建逐渐变大的临时 list
s,通过复制 所有内容 构建下一个临时文件后丢弃最后一个临时文件到目前为止,我一遍又一遍地看到新东西。如果第一个列表中有一百万个项目,并且您还有十个 list
可以连接到它上面,那么您将复制至少一千万个元素(即使其他十个 list
是空的).您的原始代码实际上更好,因为使用 +=
运算符执行就地扩展,在 O(n)
中保持最坏情况的性能(对于所有 list
中的 n
元素s) 范围,而不是 O(n*m)
(对于 m
list
s 中的 n
个元素)。
它也有只对一种一致的类型起作用的问题;如果一些输入是 list
s,一些是 tuple
s 和一些生成器,sum
将不起作用(因为 list.__add__
不会接受非 list
另一边的操作数)。
所以不要那样做。这是 what itertools.chain
and it's alternate constructor, itertools.chain.from_iterable
were made for:
from itertools import chain
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joined_list = list(chain.from_iterable(list_of_lists))
它是有保证的 O(n)
,可以与你向它抛出的任何迭代一起工作,等等。
是的,很明显,如果你只得到三个 list
的三个元素,这并不重要。但是,如果输入可迭代对象的大小或可迭代对象的数量任意大,或者类型不一致,chain
会起作用,sum
不会。