Concaténation de Listes en Python

Tout ça est repris des discussions sur quora.com en français.

Si vous voulez concaténer vos deux listes, alors le + fonctionne très bien pour ça :

a, b = [1, 2, 3], [3, 4]
print(a + b)
[1, 2, 3, 3, 4]

On peut également ajouter une seconde liste à la première avec la méthode append (cette opération modifie la première liste) :

a.append(b)
print(a)
[1, 2, 3, [3, 4]]

Si on veut la liste des éléments uniques dans les deux listes, alors une liste n’est pas la structure de données adaptée ; il faut utiliser un set (ensemble, en anglais). On peut alors utiliser soit la méthode union soit | pour fusionner nos deux ensembles :

set(a).union(b)
{1, 2, 3, 4}
set(a) | set(b)
{1, 2, 3, 4}

Si on veut la liste des paires d’éléments dans nos deux listes, on peut utiliser zip :

list(zip(a, b))
[(1, 3), (2, 4)]

Comme on peut le constater, zip s’arrête après avoir atteint le dernier élément de la liste la plus courte ; il y a une autre méthode du module itertools zip_longest qui permet de zipper jusqu’à la liste la plus longue :

import itertools as it
list(it.zip_longest(a, b))
[(1, 3), (2, 4), (3, None)]

Si on veut une liste alternée des éléments de nos deux listes, on peut faire appel à la fonction chain.from_iterable combinée à zip :

list(it.chain.from_iterable(it.zip_longest(a, b)))
[1, 3, 2, 4, 3, None]

Comme on peut le constater, cette approche laisse le None qu’on voudrait bien sûr enlever ; il suffit donc de le filtrer avec une interpolation de liste :

[x for x in it.chain.from_iterable(it.zip_longest(a, b)) if x]
[1, 3, 2, 4, 3]

Si vous voulez fusionner deux listes de façon ordonnée, il commence à y avoir pas mal d’approches différentes, en fonction de ce dont vous avez besoin de faire à partir de la liste. En pur Python, il y a trois approches possibles, principalement, en plus de potentiels packages extérieurs (Python Sorted Containers a l’air d’en être un particulièrement intéressant).

La première approche est tout simplement de trier la liste après chaque insertion, une solution tout à fait légitime si la liste n’est pas trop grande, mais d’une complexité catastrophique lorsqu’on a besoin de bonnes performances :

sorted(a + b)
[1, 2, 3, 3, 4]

La seconde est d’utiliser le module bisect, qui permet de trouver rapidement le lieu d’insertion d’un élément dans une liste triée ; il faut pour cela que la liste d’insertion soit déjà triée :

import bisect
for elem in b: bisect.insort(a, elem)
a
[1, 2, 3, 3, 4]

La troisième enfin, est d’utiliser une heapq ; c’est une option extrêmement efficace, mais qui limite grandement l’utilisation que l’on peut faire de notre structure de données. À n’utiliser que si on a besoin d’insérer des éléments et de trouver les n premiers / derniers éléments ; c’est une structure beaucoup moins flexible :

import heapq
a, b = [1, 3, 7, 2, 5], [2, 6, 3]
c = list(heapq.merge(a, b))
c
[1, 2, 3, 6, 3, 7, 2, 5]
heapq.nsmallest(3, c)
[1, 2, 2]
heapq.nlargest(3, c)
[7, 6, 5]

Comme vous pouvez le constater, bien que la liste ne soit pas du tout ordonnée, le module heapq reste tout à fait capable d’extraire sans souci les min/max, avec d’excellentes performances.