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

例子:

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

预期结果:

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

当前回答

使用简单的列表理解:

joined_list = [item for list_ in [list_one, list_two] for item in list_]

它具有使用Additional Unpacking Generalization的最新方法的所有优点-即,您可以以这种方式连接任意数量的不同可迭代项(例如,列表、元组、范围和生成器)-并且它不限于Python 3.5或更高版本。

其他回答

Python>=3.5可选:[*l1,*l2]

通过接受PEP 448引入了另一种备选方案,值得一提。

名为Additional Unpacking Generalization的PEP在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]

因为它将首先解压缩可迭代内容,然后简单地从内容创建一个列表。

这很简单,我认为它甚至在教程中显示了:

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

使用简单的列表理解:

joined_list = [item for list_ in [list_one, list_two] for item in list_]

它具有使用Additional Unpacking Generalization的最新方法的所有优点-即,您可以以这种方式连接任意数量的不同可迭代项(例如,列表、元组、范围和生成器)-并且它不限于Python 3.5或更高版本。

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

截至3.9,这些是在Python中连接两个(或更多)列表的最流行的stdlib方法。

Version Restrictions In-Place? Generalize to N lists?
a+b - No sum([a, b, c], [])1
list(chain(a,b))2 >=2.3 No list(chain(a, b, c))
[*a, *b]3 >=3.5 No [*a, *b, *c]
a += b - Yes No
a.extend(b) - Yes No

脚注这是一个巧妙的解决方案,因为它简洁。但sum以成对的方式执行连接,这意味着这是一个必须为每个步骤分配作为存储器的二次运算。做如果您的列表很大,请不要使用。参见链条和链接from_iteable从文档中。您需要首先从itertools导入链。级联在内存中是线性的,因此在性能和版本兼容性。chain.from_iteable在2.6中引入。此方法使用附加解包泛化(PEP 448),但不能归纳为N个列表,除非您自己手动打开每个列表。a+=b和a.extend(b)在所有实际用途中或多或少是等效的。+=当在列表中调用时,将在内部调用列表__iadd_,它将第一个列表扩展第二个列表。


表演

2-列表连接1

这些方法之间没有太大区别,但这是有意义的,因为它们都具有相同的复杂性(线性)。除了风格上的问题外,没有特别的理由更喜欢一个而不是另一个。

N-列表连接

已使用perfplot模块生成绘图。代码,供您参考。

1.iadd(+=)和extend方法在适当的地方运行,因此每次测试前都必须生成一个副本。为了保持公平,所有方法都有左侧列表的预复制步骤,可以忽略。


对其他解决方案的评论

不要使用DUNDER方法列表__以任何方式、形状或形式直接添加__。事实上,请不要使用dunder方法,并像设计的那样使用运算符和运算符函数。Python有精心设计的语义,这些语义比直接调用dunder更复杂。这里有一个例子。综上所述,a.__add__(b)=>BAD;a+b=>良好。这里的一些答案为成对串联提供了reduce(operator.add,[a,b])——这与sum([a,b],[])相同,只是更加冗长。任何使用set的方法都会删除重复项并丢失排序。小心使用。对于b中的i:a.append(i)比a.extend(b)更冗长,也更慢,后者是单函数调用,更惯用。由于为列表分配和增长内存的语义,append速度较慢。有关类似的讨论,请参见此处。heapq.mmerge可以工作,但它的用例是在线性时间内合并排序列表。在任何其他情况下使用它都是一种反模式。从函数中生成列表元素是一种可以接受的方法,但chain可以更快更好地实现这一点(它有一个C语言的代码路径,所以速度很快)。operator.add(a,b)是一个可接受的等价于a+b的函数。它的用例主要用于动态方法调度。否则,在我看来,更喜欢a+b,它更简短,更易读。YMMV。

我假设您需要以下两种方法之一:

保留重复元素

这很容易。就像字符串一样连接:

def concat_list(l1,l2):
    l3 = l1+l2
    return l3

接下来,如果要消除重复元素

def concat_list(l1,l2):
   l3 = []
   for i in [l1,l2]:
     for j in i:
       if j not in l3:
         # Check if element exists in final list, if no then add element to list
         l3.append(j)
   return l3