2012-04-05 20 views
7

¿Existe una forma elegante de python para eliminar elementos vacíos de una lista? Una especie de list.rstrip (Ninguno). Asíeliminación de elementos vacíos finales en Python

[1, 2, 3, None, 4, None, None] 

debería resultar en

[1, 2, 3, None, 4] 

supongo que esto podría ser generalizado a la eliminación de los elementos de salida de cualquier valor particular.


ACTUALIZACIÓN: Yo debería haber especificado que quiero que este hecho como una sola línea (legible) la expresión

+2

¿Qué pasa con un bucle? No todos los trazados son legibles. Votación a la baja debido a su actualización – Abhijit

+2

Aquí hay una sola línea (legible) expresión: 'strip_trailing_empty_elements (the_list)'. Le sugiero que use una de las respuestas que se le han dado para definir 'strip_trailing_empty_elements()', – Duncan

+1

Como dije, quiero un "lider" legible (que siempre es más legible que un loop). Si no crees que haya algo así, esa es la respuesta a mi pregunta. Entonces, ¿por qué downvote? –

Respuesta

14

Editado: Para utilizar pop() en lugar de cortar la lista, como comentaristas tienen correctamente sugerido.

No sé si hay una manera más Pythonic, pero esto funciona:

my_list = [1, 2, 3, None, 4, None, None] 
while not my_list[-1]: 
    my_list.pop() 
print my_list 
>>>[1, 2, 3, None, 4] 

Editar: Como @DSM señala, si sólo quería deshacerse de None valores y dejar ceros u otros valores Falsy, que podían hacer:

while my_list and my_list[-1] is None: 
    my_list.pop() 
+1

Esto también eliminaría ceros al final (y cualquier otra cosa falsea) – DSM

+2

Esto crearía copias innecesarias en cada iteración – Abhijit

+0

@DSM Bastante correcto. Editado la respuesta para tener eso en cuenta. – alan

7

las siguientes comprobaciones explícitamente None elementos:

while l and l[-1] is None: 
    l.pop() 

se puede generalizar de la siguiente manera:

f = lambda x: x is None 
while l and f(l[-1]): 
    l.pop() 

Ahora puede definir diferentes funciones para f para comprobar si hay otras condiciones.

+0

por favor vea mi actualización –

+2

Buena solución, pero arroja una excepción cuando una lista contiene solo Nones. Tal vez 'mientras que l y f (l [-1])' – georg

+0

@ thg435: sí, tienes razón. He agregado tu modificación a la publicación, gracias. –

2

Prueba este

>>> x=[1, 2, 3, None, 4, None, None] 
>>> while x[-1] is None: 
    x.pop() 
+0

por favor vea mi actualización –

+0

su respuesta es como la respuesta del alan, puede agregar un voto a su respuesta en lugar de emitir una nueva respuesta. – pylover

+2

@pylover: la respuesta de alan crea copias innecesarias. Debería haber usado pop en su lugar. – Abhijit

1

Para una solución de una sola línea:

In [30]: from itertools import dropwhile 

In [31]: list(reversed(tuple(dropwhile(lambda x: x is None, reversed([1, 2, 3, None, 4, None, None]))))) 
Out[31]: [1, 2, 3, None, 4] 

Si desea volver a utilizar, aquí está una definición de estilo libre de puntos:

In [36]: from functional import compose, partial 

In [37]: varargs = lambda *args: args 

In [38]: compose_mult = compose(partial(reduce, compose),varargs) # compose which takes variable number of arguments. Innermost function to the right. 

In [39]: compose_mult(list, reversed, tuple, partial(dropwhile, lambda x: x is None), reversed)([1, 2, 3, None, 4, None, None]) 
Out[39]: [1, 2, 3, None, 4] 
+0

Funciona, pero sacrifica la legibilidad demasiado en mi opinión. –

+0

@SimeonVisser Esa es una cuestión de opinión, pero sí, no estoy loco por la necesidad de forzar a una tupla en el medio. – Marcin

3
def remove_trailing(l, remove_value=None): 
     i = len(l) 
     while i>0 and l[i-1] == remove_value: 
      i -= 1 
     return l[:i] 
+0

Esta es la mejor respuesta con diferencia. Otra variación sería una asignación de división in situ en lugar de devolver la división para conservar la separación de comando/consulta.Si te gusta eso Este es un buen estilo funcional. – aaronasterling

+0

@aaronasterling Me gusta esta solución también. Estoy tratando de aprender más sobre el estilo funcional. ¿A qué te refieres con __ en lugar de la asignación de sector__. ¿Simplemente asignando la porción nuevamente al parámetro 'l'? Y no devolverlo? (Seguramente que no) – alan

+0

@alan, en lugar de 'return l [: i]', sería 'l [:] = l [: i]'. Eso lo convierte en un comando en el sentido de que cambiaría el estado de 'l'. Estaba fuera de base porque actualmente es una consulta (devuelve datos y no cambia el estado) para que conserve la separación de consultas de comandos. Me imaginaba usarlo como 'l = remove_trailing (l)' y _that_ violaría la separación de CQ, _imo_. Probablemente estoy siendo demasiado pedante aquí. – aaronasterling

0

Aquí hay otro one-liner:

>>> l = [1, 2, 3, None, 4, None, None] 
>>> [l[i] for i in range(len("".join(map(lambda x: {None: " "}.get(x, "_"), l)).rstrip()))] 
[1, 2, 3, None, 4] 

¡Estas cosas son divertidas!

EDITAR

me he dado cuenta de que la lista de comprensión es completamente innecesario. Rebanar debería funcionar bien:

>>> l[:len("".join(map(lambda x: {None: " "}.get(x, "_"), l)).rstrip())] 
+0

Y hace uso de 'rstrip()', aunque de una manera muy indirecta. –

1

Si realmente necesita comprometer la legibilidad esto es lo que yo haría.

>>> from itertools import takewhile 
>>> l=[1,2,3,None,4,5,None,None] 
>>> l[:-len(list(takewhile(lambda x: x==None, reversed(l))))] 
[1,2,3,None,4,5] 
+0

Parece de su salida que esto no logra nada. – Marcin

+0

Copie pegado la línea incorrecta, en su lugar se logra el resultado correcto y apuesto más rápido que muchas otras soluciones – luke14free

0

¿Qué hay de recursion + slicing?

>>> rstrip = lambda x, elts=(None,): rstrip(x[:-1], elts) if x and x[-1] in elts else x 
>>> rstrip([1, 2, 3, None]) 
[1, 2, 3] 
>>> rstrip([1, 2, 3, None], (None, 3)) 
[1, 2] 

Nota: Estoy asumiendo que usted no está buscando la solución más eficiente computacionalmente aquí ...

0

¿Qué hay de:

[a[i] for i in range(len(a)) if a[i:] != [None] * (len(a) - i) ] 
1

Nunca acepté una respuesta porque no estaba realmente feliz con las soluciones ofrecidas. Aquí hay otra solución (1 línea y sin dependencias de la biblioteca) que no estoy del todo contento con:

a = [1, 2, None, 3, None, None] 
reduce(lambda l, e: [e]+l if l or e is not None else [], reversed(a), []) 
+0

Sería bueno si https://docs.python.org/3.6/library/stdtypes.html#str.rstrip existiera para listas Pero como no funciona, el bucle pop de dos líneas de alan funciona para mí. – Dave

0

El proyecto more_itertools implementa rstrip para cualquier iterable:

iterable = [1, 2, 3, None, 4, None, None] 
list(mit.rstrip(iterable, lambda x: x in {None})) 
# [1, 2, 3, None, 4] 

more_itertools.rstrip acepta un iterable y predicado . Vea el source code para más detalles.

Cuestiones relacionadas