如何在Python中连接两个列表?

3238

如何在Python中连接两个列表?

示例:

listone = [1, 2, 3]
listtwo = [4, 5, 6]

预期结果:

>>> joinedlist
[1, 2, 3, 4, 5, 6]

13
你是想简单地添加,还是希望以排序的方式合并这两个列表?对于 [1,3,6] 和 [2,4,5],你期望得到什么输出?我们可以假设这两个子列表已经按顺序排列(就像你的示例中一样)吗? - smci
3
如果列表中有重复项,例如 [1,2,5][2,4,5,6],您希望重复项被包含在内、排除在外还是不关心? - smci
8
我在YouTube上制作了一个关于如何连接列表的教程,如果有人发现有用的话可以去观看 https://www.youtube.com/watch?v=O5kJ1v9XrDw - Brendan Metcalfe
31个回答

5407

使用+运算符来组合列表:

listone = [1, 2, 3]
listtwo = [4, 5, 6]

joinedlist = listone + listtwo

输出:

>>> joinedlist
[1, 2, 3, 4, 5, 6]

161
这会创建列表one的深拷贝并将列表two附加到其末尾吗? - Daniel F
211
它将创建一个新列表,其中包含第一个列表中项目的浅层副本,后跟第二个列表中项目的浅层副本。使用 copy.deepcopy 来获取列表的深层副本。 - Daniel G
311
这里还有一个有用的细节:listone += listtwo 的结果是 listone == [1, 2, 3, 4, 5, 6] - rickcnagy
22
@br1ckb0t这样做会改变listone所指向的内容吗?那么,当执行以下代码时:list3 = listone listone+=listtwo,list3是否也会发生改变? - MikeH
9
@Pygmalion 这与 Python3 无关,而是特定于 NumPy 数组处理运算符的方式。查看 Robert Rossney 的答案中 J.F. Sebastian 给出的有关连接 NumPy 数组的方法。 - 153957
显示剩余8条评论

638

Python >= 3.5 的替代方案:[*l1, *l2]

另外还有一种选择是通过接受 PEP 448 引入的,值得一提。

这个 PEP 名为 Additional Unpacking Generalizations,通常情况下降低了使用星号表达式 * 在 Python 中的某些语法限制;使用它后,将两个列表连接(适用于任何可迭代对象)也可以使用以下方式进行:

>>> l1 = [1, 2, 3]
>>> l2 = [4, 5, 6]
>>> joined_list = [*l1, *l2]  # unpack both iterables in a list literal
>>> print(joined_list)
[1, 2, 3, 4, 5, 6]

这个功能在Python 3.5中定义,但是它没有被移植到3.x系列中的早期版本。在不受支持的版本中,会引发SyntaxError

和其他方法一样,这种方法也会为相应列表中的元素创建一个浅拷贝。


这种方法的好处是您真的不需要列表才能执行它;任何可迭代的东西都可以。正如PEP中所述:

这也是一种更易读的将可迭代对象求和为列表的方法,例如my_list + list(my_tuple) + list(my_range),现在等同于[*my_list, *my_tuple, *my_range]

因此,虽然使用+进行加法会由于类型不匹配而引发TypeError

l = [1, 2, 3]
r = range(4, 7)
res = l + r
以下内容不会:
res = [*l, *r]

因为它将首先解包可迭代对象的内容,然后仅从这些内容创建一个list


23
unpacking方法在可迭代类型上的一个很好的例子是那些返回你正在连接的列表中一个迭代器的函数。比如,你可以翻转你连接的列表之一:res = [*l1, *reversed(l2)]。因为reversed返回一个迭代器,所以res = l1 + reversed(l2)会抛出一个错误。 - alan
13
值得注意的是,这类似于在 Python 中合并字典。使用 "**" 来展开字典,而对于列表我们使用 "*" 来展开。请注意,此处创建的新字典为 dict3 = {**dict1, **dict2}。 - Kevin S
8
好的,我会尽力为您提供准确且易于理解的翻译,以下是所需翻译的内容:我内心的语法纠正家必须指出:*字典 - Marcello Romani
1
@KevinS 这仅适用于字符串键,因为 ** 语法仅支持字符串键。 - user16829600
2
非常有趣。你知道这种方法与加法相比的性能如何吗? - AlexandreBorowczyk
显示剩余2条评论

404

也可以使用itertools.chain()创建一个生成器,它只是简单地遍历两个列表中的项。这允许您将列表(或任何可迭代对象)链接在一起进行处理,而无需将项复制到新列表中:

import itertools
for item in itertools.chain(listone, listtwo):
    # Do something with each list item

11
在两个列表中,chain 的速度比较慢(但差距不大),但对于链接多个列表(n >> 2),它是最快的解决方案。 - cs95
@cs95 相对于什么而言慢? - Moberg
1
@Moberg 相比其他列表连接的方式,请参见我的基准测试此处 - cs95
1
@cs95 你的基准测试使用 chain 来创建一个迭代器,遍历所有元素并将结果转换为列表。有时这正是你想要的,但如果你只是想遍历所有元素,那么可以直接使用 chain 的迭代器。这样可能会更快。 - Roel Schroeven

348

如何在Python中连接两个列表?

截至3.9版本,以下是Python中连接两个(或多个)列表最流行的标准库方法。

版本限制原地操作?泛化?*
a + b-sum(list_of_lists, [])1
list(chain(a, b))2>=2.3list(chain(*list_of_lists))
[*a, *b]3>=3.5
a += b-
a.extend(b)-

* 如果一个解决方案适用于未知数量的列表(例如,在循环或列表推导中),则它将被视为通用解决方案。

脚注

  1. 这是一种简洁的解决方案,因为它很简短。但是sum以成对的方式执行连接,这意味着这是一个二次操作,因为必须为每个步骤分配内存。如果您的列表很大,请勿使用。

  2. 请参见文档中的chainchain.from_iterable。您需要首先from itertools import chain。连接在内存中是线性的,因此在性能和版本兼容性方面,这是最好的选择。chain.from_iterable是在2.6中引入的。

  3. 此方法使用附加解包概括(PEP 448),但除非您自己手动解包每个列表,否则无法推广到N个列表。

  4. a += ba.extend(b)在实际目的上或多或少是等效的。+=在列表上调用时将内部调用list.__iadd__,该方法通过第二个列表扩展第一个列表。


性能

2-列表连接1

enter image description here

这些方法之间没有太大的区别,但考虑到它们都具有相同的复杂度顺序(线性),这是有道理的。除了风格问题外,没有特别偏好其中任何一种。

N-列表连接

enter image description here

使用perfplot模块生成了图表。代码,供参考。

1. iadd+=)和extend方法是原地操作,因此每次测试之前都必须生成副本。为了保持公平,所有方法都有一个用于左侧列表的预复制步骤,可以忽略。


对其他解决方案的评论

  • 不要直接使用 DUNDER 方法 list.__add__ 任何方式,形式来操作它。事实上,应该避免使用DUNDER方法,而是像设计时那样使用操作符和operator函数。Python在这些操作中有谨慎的语义,比直接调用DUNDER更复杂。这里是一个例子。因此,总结一下:a.__ add__(b) => 不好;a + b => 好。

  • 这里有一些答案提供了reduce(operator.add, [a, b])用于成对拼接 - 这与sum([a, b], [])相同,只是更冗长。

  • 任何使用set的方法都将删除重复项并失去排序。请谨慎使用。

  • for i in b: a.append(i)a.extend(b)更冗长,更慢,后者是单个函数调用,更习惯用法。由于列表的内存分配和增长的语义,append更慢。参见 here类似的讨论。

  • heapq.merge可以工作,但它的用例是在线性时间内合并排序列表。在任何其他情况下使用它都是反模式。

  • 从函数中yield元素列表是一种可接受的方法,但是chain可以更快,更好地执行此操作(它有一个C代码路径,因此很快)。

  • operator.add(a, b)a + b的可接受的函数等价物。其主要用途是动态方法分派。否则,建议使用更短、更易读的a + b,这是我的意见。你的经验可能会有所不同。


回答 https://dev59.com/S5bfa4cB1Zd3GeqPuHYb 可以使用 perfplot 绘制图表(包括 numba 解决方案)。 - endolith
@endolith 有点忙于工作,但我会看一下并尽力帮忙。谢谢。 - cs95
2
哪种方法在性能方面最好,更快的那个?请告诉我。 - GD- Ganesh Deshmukh
3
TL;DR 是它们都很好,你选择哪一个主要是风格问题。 “这些方法之间没有太大的区别,但考虑到它们都具有相同的复杂度(线性),这是有道理的。没有特别的理由喜欢其中任何一种,除非是出于风格的原因。” 我建议不使用我答案中未列出的解决方案或在“评论”中受到批评的解决方案。 - cs95
还有[i for ls in list_of_lists for i in ls]。如果能把它包含在列表和图表中就太好了。 :) - undefined
显示剩余2条评论

309

你还可以使用list.extend()方法来将一个list添加到另一个列表的末尾:

listone = [1,2,3]
listtwo = [4,5,6]

listone.extend(listtwo)
如果您想保留原始列表不变,可以创建一个新的list对象,并将两个列表extend到它上面:
mergedlist = []
mergedlist.extend(listone)
mergedlist.extend(listtwo)

2
为什么这个方法在我的情况下返回None - Ayush
1
listone = [1,2,3]; listtwo = [4,5,6]; listone.extend(listtwo) this returns me None - Ayush
8
它对 listone 进行原地更新,因此请检查它是否在列表 listone 中。 - Gourneau
1
实际上,我正在返回一个表达式,在该表达式中,我使用您提到的方法扩展了一个列表。我没有像这篇文章中所说的那样重新分配列表。我的表达式类似于return list1.extend(list2),而这个表达式对我返回了None - Ayush
3
@Ayush,extend方法会使用listtwo的值更新listone,并返回None。你想要做的是:先执行listone.extend(listtwo),然后返回listone。 - Andrew

263
你可以使用集合来获取合并后的唯一值列表。
mergedlist = list(set(listone + listtwo))

64
是的,然而它也会删除重复项,如果这是你感兴趣的。仅仅添加到列表中是做不到这一点的。 - metasoarous
2
如何做到这一点并保留排序信息? - Natim
16
比“listone + [x for x in listtwo if x not in listone]”更好。 - Natim
9
在我看来,这是“合并”列表的正确方法(并集),而“批准”的回答描述了如何组合/添加列表(多重集)。 - Nir Alfasi
5
如果您关心保持输入顺序,则可以使用import collections; mergedlist = list(collections.OrderedDict.fromkeys(listone + listtwo))来解决问题。 - SethMMorton
1
如果您关心维护顺序,在CPython 3.6+上,您可以执行mergedlist = list(dict.fromkeys(listone + listtwo)) - user3064538

95

这很简单,而且我认为甚至在教程中已经展示过了:

>>> listone = [1,2,3]
>>> listtwo = [4,5,6]
>>>
>>> listone + listtwo
[1, 2, 3, 4, 5, 6]

72

这个问题直接询问如何合并两个列表。然而,即使你正在寻找一种合并许多列表的方法(包括合并零个列表的情况),它在搜索结果中也非常高。

我认为最好的选择是使用列表推导式:

>>> a = [[1,2,3], [4,5,6], [7,8,9]]
>>> [x for xs in a for x in xs]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
你也可以创建生成器:

你也可以创建生成器:

>>> map(str, (x for xs in a for x in xs))
['1', '2', '3', '4', '5', '6', '7', '8', '9']

旧回答

考虑这种更通用的方法:

a = [[1,2,3], [4,5,6], [7,8,9]]
reduce(lambda c, x: c + x, a, [])

将输出:

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

请注意,当 a[][[1,2,3]] 时,此方法也可以正确地工作。

然而,使用 itertools 可以更加高效。

a = [[1,2,3], [4,5,6], [7,8,9]]
list(itertools.chain(*a))
如果您不需要一个列表,只需要一个可迭代对象,请省略list()。 更新 评论中Patrick Collins提出的另一种替代方法也可能适合您:
sum(a, [])

7
Python 3的注意事项:现在reduce函数在functools模块中,所以您需要先导入它。 - Dimitris Fasarakis Hilliard

50
您可以使用以下方式简单地使用++=运算符:
a = [1, 2, 3]
b = [4, 5, 6]

c = a + b

或者:

c = []
a = [1, 2, 3]
b = [4, 5, 6]

c += (a + b)
此外,如果您希望合并列表中的值是唯一的,可以执行以下操作:
c = list(set(a + b))

2
最后一部分可以任意重新排列项目。如果您想保留顺序,在CPython 3.6+上,您可以执行list(dict.fromkeys(a + b)) - user3064538

36
值得注意的是,itertools.chain 函数接受可变数量的参数:
>>> l1 = ['a']; l2 = ['b', 'c']; l3 = ['d', 'e', 'f']
>>> [i for i in itertools.chain(l1, l2)]
['a', 'b', 'c']
>>> [i for i in itertools.chain(l1, l2, l3)]
['a', 'b', 'c', 'd', 'e', 'f']

如果输入的是可迭代对象(元组、列表、生成器等),可以使用from_iterable类方法:

>>> il = [['a'], ['b', 'c'], ['d', 'e', 'f']]
>>> [i for i in itertools.chain.from_iterable(il)]
['a', 'b', 'c', 'd', 'e', 'f']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,