python - tupla - ¿Cómo eliminar elementos duplicados adyacentes en una lista utilizando las comprensiones de lista?
identificar elementos repetidos en una lista python (5)
El uso de pares de las recetas de itertools (con zip_longest) le brinda una manera fácil de verificar el siguiente elemento:
import itertools as it
def pairwise(iterable):
a, b = it.tee(iterable)
next(b, None)
return it.zip_longest(a, b, fillvalue=object()) # izip_longest for Py2
>>> xs = [1,2,2,3]
>>> [x for x, y in pairwise(xs) if x != y]
[1, 2, 3]
>>> xs = [1,2,2,2,2,3,3,3,4,5,6,6]
>>> [x for x, y in pairwise(xs) if x != y]
[1, 2, 3, 4, 5, 6]
Esta pregunta ya tiene una respuesta aquí:
- Eliminar elementos duplicados adyacentes de una lista 16 respuestas
¿Hay alguna manera de usar las comprensiones de listas en python para filtrar los duplicados adyacentes de una lista?
Aquí hay un ejemplo de lo que quiero decir:
>>> xs = [1,2,2,3]
>>> print added.reAdj(xs)
[1,2,3]
Una búsqueda a través de SE reveló una consulta anterior que planteaba una pregunta similar pero ligeramente diferente: si todos los duplicados podrían eliminarse de una lista, pero no solicitar explícitamente soluciones que involucren la comprensión de listas . La motivación para usar las listas de comprensión sigue específicamente el reconocimiento de sus ventajas sobre los bucles tradicionales . Los usuarios sugirieron el uso de la función set () o el ciclo estándar como tal:
result = []
most_recent_elem = None
for e in xs:
if e != most_recent_elem:
result.append(e)
most_recent_elem = e
La sugerencia de set()
no cumple con la tarea porque se eliminan los duplicados no adyacentes, mientras que el bucle es efectivo pero detallado.
Parece un medio para hacer referencia segura al siguiente elemento en una lista de comprensión, ya que se necesita lo siguiente.
[x for x in xs if x != **x.next()**]
¿Algunas ideas?
Podría usar una solución de bucle menos verbosa:
>>> result = xs[:1]
>>> for e in xs:
if e != result[-1]:
result.append(e)
O:
>>> result = []
>>> for e in xs:
if e not in result[-1:]:
result.append(e)
Puede usar la list comprehension
y enumerate
con la solución sugerida por @AChampion:
xs = [1,2,2,2,1,1]
In [115]: [n for i, n in enumerate(xs) if i==0 or n != xs[i-1]]
Out[115]: [1, 2, 1]
Esa lista de comprensión devuelve el elemento si es el primero o el siguiente si no es igual al anterior. Funcionará debido a las perezosas evaluaciones de la sentencia if
.
Puedes usar itertools.groupby
:
>>> import itertools
>>> [key for key, grp in itertools.groupby([1, 2, 2, 3])]
[1, 2, 3]
itertools.groupby
devuelve un iterador. Al iterarlo, obtendrás una clave, pares de grupos. (la key
será un elemento si no se especifica ninguna función de key
; de lo contrario, el valor de retorno de la función de key
). group
es un iterador que produce elementos agrupados aplicando la función de key
(si no se especifica, se agruparán los mismos valores)
>>> import itertools
>>> it = itertools.groupby([1, 2, 2, 3])
>>> it
<itertools.groupby object at 0x7feec0863048>
>>> for key, grp in it:
... print(key)
... print(grp)
...
1
<itertools._grouper object at 0x7feec0828ac8>
2
<itertools._grouper object at 0x7feec0828b00>
3
<itertools._grouper object at 0x7feec0828ac8>
>>> it = itertools.groupby([1, 2, 2, 3])
>>> for key, grp in it:
... print(list(grp))
...
[1]
[2, 2]
[3]
Por encima de la solución, usé solo la key
porque a la pregunta no le importa cuántos elementos son adyacentes.
Qué tal esto:
>>> l = [1,1,2,3,4,4,4,4,5,6,3,3,5,5,7,8,8,8,9,1,2,3,3,3,10,10]
>>>
>>> o = []
>>> p = None
>>> for n in l:
if n == p:
continue
o.append(n)
p = n
>>> o
[1, 2, 3, 4, 5, 6, 3, 5, 7, 8, 9, 1, 2, 3, 10]
Aparentemente, la solución anterior es más detallada que las OP, por lo que aquí hay una alternativa a la que usa zip_longest
desde el módulo itertools
:
>>> l
[1, 1, 2, 3, 4, 4, 4, 4, 5, 6, 3, 3, 5, 5, 7, 8, 8, 8, 9, 1, 2, 3, 3, 3, 10, 10]
>>> from itertools import zip_longest
>>> o = [p for p,n in zip_longest(l,l[1:]) if p != n] #By default fillvalue=None
>>> o
[1, 2, 3, 4, 5, 6, 3, 5, 7, 8, 9, 1, 2, 3, 10]