funciona solo si l1 y l2 tienen el mismo número de elementos
Emmanuel
14
@Emmanuel: La pregunta dice "En Python, ¿hay una buena manera de intercalar dos listas de la misma longitud ?"
NPE
1
Si desea izip_longestsubir a la lista más larga, use para python2 y zip_longestpara los [val for pair in itertools.zip_longest(l1, l2) for val in pair]resultados de python3 con['a', 'b', 'a', 'b', 'a', 'b', None, 'b', None, 'b', None, 'b']
>>> a = [0, 2, 4, 6, 8]
>>> b = [1, 3, 5, 7, 9]
>>> c = a + b
>>> c[::2] = a
>>> c[1::2] = b
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
La línea c = a + bse utiliza como una forma sencilla de crear una nueva lista de exactamente la longitud correcta (en esta etapa, su contenido no es importante). Las siguientes dos líneas hacen el trabajo real de intercalado ay b: la primera asigna los elementos de aa todos los índices pares de c; el segundo asigna los elementos de ba todos los índices impares de c.
>>> l1=[1,2,3]
>>> l2=[10,20,30]
>>> [y for x in map(None,l1,l2) for y in x if y isnotNone]
[1, 10, 2, 20, 3, 30]
Esto funciona porque map funciona en listas en paralelo. Se trabaja de la misma en el punto 2.2. Por sí mismo, con Nonelas funciones llamadas, mapproduce una lista de tuplas:
La ventaja, por supuesto, es map que funcionará para cualquier número de listas y funcionará incluso si tienen diferentes longitudes:
>>> l1=[1,2,3]
>>> l2=[10,20,30]
>>> l3=[101,102,103,104]
>>> [y for x in map(None,l1,l2,l3) for y in x if y innotNone]
[1, 10, 101, 2, 20, 102, 3, 30, 103, 104]
if yse filtrará 0también, if y is not Nonees menos frágil.
Jochen Ritzel
@Jochen Ritzel: ¡Gracias! Estoy de acuerdo contigo. Fijo. La escribí con sólo los músculos involucrados ...
el lobo
3
Me gusta más la solución de Aix. aquí hay otra forma que creo que debería funcionar en 2.2:
>>> x=range(3)
>>> x
[0, 1, 2]
>>> y=range(7,10)
>>> y
[7, 8, 9]
>>> sum(zip(x,y),[])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not"tuple") to list
>>> sum(map(list,zip(x,y)),[])
[0, 7, 1, 8, 2, 9]
y una forma más:
>>> a=[x,y]
>>> [a[i][j] for j in range(3) for i in (0,1)]
[0, 7, 1, 8, 2, 9]
y:
>>> sum((list(i) for i in zip(x,y)),[])
[0, 7, 1, 8, 2, 9]
Para responder al título de la pregunta de "Intercalar varias listas de la misma longitud en Python", podemos generalizar la respuesta de 2 listas de @ekhumoro. Esto requiere explícitamente que las listas tengan la misma longitud, a diferencia de la solución (elegante) de @NPE
import itertools
definterleave(lists):"""Interleave a list of lists.
:param lists: List of lists; each inner length must be the same length.
:returns: interleaved single list
:rtype: list
"""if len(set(len(_) for _ in lists)) > 1:
raise ValueError("Lists are not all the same length!")
joint = list(itertools.chain(*lists))
for l_idx, li in enumerate(lists):
joint[l_idx::len(lists)] = li
return joint
it = iter(l1); list((yield next(it)) or i for i in l2)
Respuestas:
Después de haber publicado la pregunta, me di cuenta de que simplemente puedo hacer lo siguiente:
[val for pair in zip(l1, l2) for val in pair]
donde
l1
yl2
son las dos listas.Si hay N listas para intercalar, entonces
lists = [l1, l2, ...] [val for tup in zip(*lists) for val in tup]
fuente
izip_longest
subir a la lista más larga, use para python2 yzip_longest
para los[val for pair in itertools.zip_longest(l1, l2) for val in pair]
resultados de python3 con['a', 'b', 'a', 'b', 'a', 'b', None, 'b', None, 'b', None, 'b']
Para Python> = 2.3, hay una sintaxis de segmento extendida :
>>> a = [0, 2, 4, 6, 8] >>> b = [1, 3, 5, 7, 9] >>> c = a + b >>> c[::2] = a >>> c[1::2] = b >>> c [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
La línea
c = a + b
se utiliza como una forma sencilla de crear una nueva lista de exactamente la longitud correcta (en esta etapa, su contenido no es importante). Las siguientes dos líneas hacen el trabajo real de intercaladoa
yb
: la primera asigna los elementos dea
a todos los índices pares dec
; el segundo asigna los elementos deb
a todos los índices impares dec
.fuente
Dado
a = [1, 2, 3] b = [10, 20, 30] c = [100, 200, 300, 999]
Código
Suponiendo listas de igual longitud, puede obtener una lista intercalada con
itertools.chain
yzip
:import itertools list(itertools.chain(*zip(a, b))) # [1, 10, 2, 20, 3, 30]
Alternativas
itertools.zip_longest
De manera más general con listas desiguales, use
zip_longest
(recomendado):[x for x in itertools.chain(*itertools.zip_longest(a, c)) if x is not None] # [1, 100, 2, 200, 3, 300, 999]
Muchas listas se pueden intercalar de forma segura:
[x for x in itertools.chain(*itertools.zip_longest(a, b, c)) if x is not None] # [1, 10, 100, 2, 20, 200, 3, 30, 300, 999]
more_itertools
+Una biblioteca que se envía con la
roundrobin
receta de itertoolsinterleave
yinterleave_longest
.import more_itertools list(more_itertools.roundrobin(a, b)) # [1, 10, 2, 20, 3, 30] list(more_itertools.interleave(a, b)) # [1, 10, 2, 20, 3, 30] list(more_itertools.interleave_longest(a, c)) # [1, 100, 2, 200, 3, 300, 999]
yield from
Finalmente, para algo interesante en Python 3 (aunque no recomendado):
list(filter(None, ((yield from x) for x in zip(a, b)))) # [1, 10, 2, 20, 3, 30] list([(yield from x) for x in zip(a, b)]) # [1, 10, 2, 20, 3, 30]
+ Instalar usando
pip install more_itertools
fuente
Necesitaba una forma de hacer esto con listas de diferentes tamaños que la respuesta aceptada no aborda.
Mi solución usa un generador y su uso se ve un poco mejor por eso:
def interleave(l1, l2): iter1 = iter(l1) iter2 = iter(l2) while True: try: if iter1 is not None: yield next(iter1) except StopIteration: iter1 = None try: if iter2 is not None: yield next(iter2) except StopIteration: iter2 = None if iter1 is None and iter2 is None: raise StopIteration()
Y su uso:
>>> a = [1, 2, 3, 4, 5] >>> b = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> list(interleave(a, b)) [1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 'e', 'f', 'g'] >>> list(interleave(b, a)) ['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 'g']
fuente
roundrobin
receta delitertools
módulo es una extensión más general de esto.Alternativa:
>>> l1=[1,2,3] >>> l2=[10,20,30] >>> [y for x in map(None,l1,l2) for y in x if y is not None] [1, 10, 2, 20, 3, 30]
Esto funciona porque map funciona en listas en paralelo. Se trabaja de la misma en el punto 2.2. Por sí mismo, con
None
las funciones llamadas,map
produce una lista de tuplas:>>> map(None,l1,l2,'abcd') [(1, 10, 'a'), (2, 20, 'b'), (3, 30, 'c'), (None, None, 'd')]
Luego, simplemente aplana la lista de tuplas.
La ventaja, por supuesto, es
map
que funcionará para cualquier número de listas y funcionará incluso si tienen diferentes longitudes:>>> l1=[1,2,3] >>> l2=[10,20,30] >>> l3=[101,102,103,104] >>> [y for x in map(None,l1,l2,l3) for y in x if y in not None] [1, 10, 101, 2, 20, 102, 3, 30, 103, 104]
fuente
if y
se filtrará0
también,if y is not None
es menos frágil.Me gusta más la solución de Aix. aquí hay otra forma que creo que debería funcionar en 2.2:
>>> x=range(3) >>> x [0, 1, 2] >>> y=range(7,10) >>> y [7, 8, 9] >>> sum(zip(x,y),[]) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can only concatenate list (not "tuple") to list >>> sum(map(list,zip(x,y)),[]) [0, 7, 1, 8, 2, 9]
y una forma más:
>>> a=[x,y] >>> [a[i][j] for j in range(3) for i in (0,1)] [0, 7, 1, 8, 2, 9]
y:
>>> sum((list(i) for i in zip(x,y)),[]) [0, 7, 1, 8, 2, 9]
fuente
[el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None]
Mientras no tengas
None
eso que quieres conservarfuente
Para responder al título de la pregunta de "Intercalar varias listas de la misma longitud en Python", podemos generalizar la respuesta de 2 listas de @ekhumoro. Esto requiere explícitamente que las listas tengan la misma longitud, a diferencia de la solución (elegante) de @NPE
import itertools def interleave(lists): """Interleave a list of lists. :param lists: List of lists; each inner length must be the same length. :returns: interleaved single list :rtype: list """ if len(set(len(_) for _ in lists)) > 1: raise ValueError("Lists are not all the same length!") joint = list(itertools.chain(*lists)) for l_idx, li in enumerate(lists): joint[l_idx::len(lists)] = li return joint
Ejemplos:
>>> interleave([[0,2,4], [1, 3, 5]]) [0, 1, 2, 3, 4, 5] >>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12]]) [0, 1, 10, 2, 3, 11, 4, 5, 12] >>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12], [13, 14, 15]]) [0, 1, 10, 13, 2, 3, 11, 14, 4, 5, 12, 15] >>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12], [13, 14]]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 10, in interleave ValueError: Lists are not all the same length! >>> interleave([[0,2,4]]) [0, 2, 4]
fuente
Demasiado tarde para la fiesta y hay muchas buenas respuestas, pero también me gustaría proporcionar una solución simple usando el
extend()
método:list1 = [1, 2, 3] list2 = [10, 20, 30] new_list = [] for i in range(len(list1)): new_list.extend([list1[i], list2[i]]) print(new_list)
Salida:
[1, 10, 2, 20, 3, 30]
fuente