python - vacia - Cree una lista de tuplas con elementos de lista adyacentes si una condición es verdadera
llenar una lista en python (6)
Estoy tratando de crear una lista de tuplas donde el contenido de la tupla es el número 9
y el número anterior en la lista.
Lista de entrada:
myList = [1, 8, 9, 2, 4, 9, 6, 7, 9, 8]
Salida deseada:
sets = [(8, 9), (4, 9), (7, 9)]
Código:
sets = [list(zip(myList[i:i], myList[-1:])) for i in myList if i==9]
Resultado actual:
[[], [], []]
Enfoque pitónico más limpio:
>>> [(x,y) for x,y in zip(myList, myList[1:]) if y == 9]
[(8, 9), (4, 9), (7, 9)]
¿Qué hace el código anterior haciendo:
-
zip(some_list, some_list[1:])
generaría una lista de pares de elementos adyacentes. - Ahora con esa tupla, filtre a condición de que el segundo elemento sea igual a
9
. Has terminado :)
Es realmente sorprendente que nadie haya agregado un enfoque funcional.
Otra respuesta alternativa es usar un filter
. Esta función incorporada devuelve un iterador (lista en Python2) que consta de todos los elementos presentes en la lista que devuelven True
para una función particular
>>> myList = [1,8,9,2,4,9,6,7,9,8]
>>> list(filter(lambda x:x[1]==9,zip(myList, myList[1:])))
[(8, 9), (4, 9), (7, 9)]
Se debe tener en cuenta que la llamada a la list
es necesaria solo en python3 + . La diferencia entre el enfoque funcional y las listas de comprensión se analiza en detalle en esta publicación .
Estuviste muy cerca, te mostraré una forma alternativa que podría ser más intuitiva si recién estás comenzando:
sets = [(myList[i-1], myList[i]) for i in range(len(myList)) if myList[i] == 9]
Obtenga el índice en el rango de la longitud de la lista, y si el valor en la posición i
es igual a 9
, tome los elementos adyacentes.
El resultado es:
sets
[(8, 9), (4, 9), (7, 9)]
Esto es menos eficiente que los otros enfoques, pero decidí quitarlo para mostrarte una manera diferente de hacerlo. Puedes hacerlo ir un poco más rápido usando enumerate()
lugar:
sets = [(myList[i-1], j) for i, j in enumerate(myList) if j == 9]
Tenga en cuenta que en el caso de borde donde myList[0] = 9
el comportamiento de la comprensión sin zip
y el comportamiento de la comprensión con zip
es diferente .
Específicamente, si myList = [9, 1, 8, 9, 2, 4, 9, 6, 7, 9, 8]
entonces:
[(myList[i-1], myList[i]) for i in range(len(myList)) if myList[i] == 9]
# results in: [(8, 9), (8, 9), (4, 9), (7, 9)]
mientras:
[(x, y) for x, y in zip(myList, myList[1:]) if y==9]
# results in: [(8, 9), (4, 9), (7, 9)]
Depende de usted decidir cuál de estos se ajusta a sus criterios, solo estoy señalando que no se comportan igual en todos los casos.
Mi solución es similar a una de las avanzadas de Jim con comprobación de índice cero
myList = [9, 1, 8, 9, 2, 4, 9, 6, 7, 9, 8]
[(myList[i-1], x) for i, x in enumerate(myList) if x==9 and i!=0]
# [(8, 9), (4, 9), (7, 9)]
Parte de su problema es que myList[i:i]
siempre devolverá una lista vacía. El final de un sector es exclusivo, por lo que cuando hace una a_list[0:0]
está intentando tomar los elementos de una a_list
que existen entre el índice 0 y el índice 0.
Estás en el camino correcto, pero quieres comprimir la lista con ella.
[(x, y) for x, y in zip(myList, myList[1:]) if y==9]
También puedes hacerlo sin cortar creando iteradores:
l = myList = [1,8,9,2,4,9,6,7,9,8]
it1, it2 = iter(l), iter(l)
# consume first element from it2 -> leaving 8,9,2,4,9,6,7,9,8
next(it2, "")
# then pair up, (1,8), (8,9) ...
print([(i, j) for i,j in zip(it1, it2) if j == 9])
O usa la receta de pares para crear tus pares.
from itertools import tee, izip
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
Si usa python3, solo importe el tee y use el zip regular.