Vous pouvez utiliser un générateur pour une solution élégante. A chaque itération, donnez deux fois -une fois avec l'élément original, et une fois avec l'élément avec le suffixe ajouté.
Le générateur devra être épuisé, ce qui peut être fait en ajoutant une carte de crédit. list
appel à la fin.
def transform(l):
for i, x in enumerate(l, 1):
yield x
yield f'{x}_{i}' # {}_{}'.format(x, i)
Vous pouvez également réécrire ceci en utilisant l'option yield from
syntaxe pour la délégation de générateur :
def transform(l):
for i, x in enumerate(l, 1):
yield from (x, f'{x}_{i}') # (x, {}_{}'.format(x, i))
out_l = list(transform(l))
print(out_l)
['a', 'a_1', 'b', 'b_2', 'c', 'c_3']
Si vous êtes sur des versions antérieures à python-3.6, remplacez f'{x}_{i}'
con '{}_{}'.format(x, i)
.
Généraliser
Considérons un scénario général où vous avez N listes de la forme :
l1 = [v11, v12, ...]
l2 = [v21, v22, ...]
l3 = [v31, v32, ...]
...
Que vous souhaitez intercaler. Ces listes ne sont pas nécessairement dérivées les unes des autres.
Pour gérer les opérations d'entrelacement avec ces N listes, vous devrez itérer sur les paires :
def transformN(*args):
for vals in zip(*args):
yield from vals
out_l = transformN(l1, l2, l3, ...)
Tranches de list.__setitem__
Je le recommande du point de vue de la performance. Commencez par allouer de l'espace à une liste vide, puis affectez les éléments de la liste à leurs positions appropriées en utilisant l'affectation de liste tranchée. l
va dans les index pairs, et l'
( l
modifié) va dans des index impairs.
out_l = [None] * (len(l) * 2)
out_l[::2] = l
out_l[1::2] = [f'{x}_{i}' for i, x in enumerate(l, 1)] # [{}_{}'.format(x, i) ...]
print(out_l)
['a', 'a_1', 'b', 'b_2', 'c', 'c_3']
C'est toujours le plus rapide d'après mes chronométrages (ci-dessous).
Généraliser
Pour gérer N listes, on assigne itérativement aux tranches.
list_of_lists = [l1, l2, ...]
out_l = [None] * len(list_of_lists[0]) * len(list_of_lists)
for i, l in enumerate(list_of_lists):
out_l[i::2] = l
Une approche fonctionnelle, similaire à la solution de @chrisz. Construisez des paires en utilisant zip
et ensuite l'aplatir en utilisant itertools.chain
.
from itertools import chain
# [{}_{}'.format(x, i) ...]
out_l = list(chain.from_iterable(zip(l, [f'{x}_{i}' for i, x in enumerate(l, 1)])))
print(out_l)
['a', 'a_1', 'b', 'b_2', 'c', 'c_3']
iterools.chain
est largement considérée comme l'approche d'aplatissement des listes pythiques.
Généraliser
C'est la solution la plus simple à généraliser, et je soupçonne que c'est la plus efficace pour les listes multiples lorsque N est grand.
list_of_lists = [l1, l2, ...]
out_l = list(chain.from_iterable(zip(*list_of_lists)))
Performance
Jetons un coup d'oeil à quelques tests de performance pour le cas simple de deux listes (une liste avec son suffixe). Les cas généraux ne seront pas testés car les résultats varient largement en fonction des données.
Code d'étalonnage, pour référence.
Fonctions
def cs1(l):
def _cs1(l):
for i, x in enumerate(l, 1):
yield x
yield f'{x}_{i}'
return list(_cs1(l))
def cs2(l):
out_l = [None] * (len(l) * 2)
out_l[::2] = l
out_l[1::2] = [f'{x}_{i}' for i, x in enumerate(l, 1)]
return out_l
def cs3(l):
return list(chain.from_iterable(
zip(l, [f'{x}_{i}' for i, x in enumerate(l, 1)])))
def ajax(l):
return [
i for b in [[a, '{}_{}'.format(a, i)]
for i, a in enumerate(l, start=1)]
for i in b
]
def ajax_cs0(l):
# suggested improvement to ajax solution
return [j for i, a in enumerate(l, 1) for j in [a, '{}_{}'.format(a, i)]]
def chrisz(l):
return [
val
for pair in zip(l, [f'{k}_{j+1}' for j, k in enumerate(l)])
for val in pair
]
0 votes
Liés : Entrelacement de deux listes en Python y La façon la plus pythique d'entrelacer deux cordes