una - listas python
Eliminar mĂșltiples elementos de una lista (24)
¿Es posible eliminar múltiples elementos de una lista al mismo tiempo? Si quiero eliminar elementos en el índice 0 y 2, y probar algo como del somelist [0], seguido de del somelist [2], la segunda declaración realmente eliminará somelist [3].
Supongo que siempre podría eliminar los elementos numerados más altos primero, pero espero que haya una mejor manera.
Aquí hay una alternativa, que no usa enumerar () para crear tuplas (como en la respuesta original de SilentGhost).
Esto me parece más legible. (Tal vez me sentiría diferente si tuviera el hábito de usar enumerar.) CAVEAT: No he probado el rendimiento de los dos enfoques.
# Returns a new list. "lst" is not modified.
def delete_by_indices(lst, indices):
indices_as_set = set(indices)
return [ lst[i] for i in xrange(len(lst)) if i not in indices_as_set ]
NOTA: sintaxis de Python 2.7. Para Python 3, xrange
=> range
.
Uso:
lst = [ 11*x for x in xrange(10) ]
somelist = delete_by_indices( lst, [0, 4, 5])
somelist:
[11, 22, 33, 66, 77, 88, 99]
--- BONIFICACIÓN ---
Eliminar múltiples valores de una lista. Es decir, tenemos los valores que queremos eliminar:
# Returns a new list. "lst" is not modified.
def delete__by_values(lst, values):
values_as_set = set(values)
return [ x for x in lst if x not in values_as_set ]
Uso:
somelist = delete__by_values( lst, [0, 44, 55] )
somelist:
[11, 22, 33, 66, 77, 88, 99]
Esta es la misma respuesta que antes, pero esta vez suministramos los VALORES que se eliminarán [0, 44, 55]
.
Como especialización de la respuesta de Greg, incluso puede usar sintaxis de segmento extendido. p.ej. Si desea eliminar los elementos 0 y 2:
>>> a= [0, 1, 2, 3, 4]
>>> del a[0:3:2]
>>> a
[1, 3, 4]
Esto no cubre ninguna selección arbitraria, por supuesto, pero ciertamente puede funcionar para eliminar dos elementos.
Como una función:
def multi_delete(list_, *args):
indexes = sorted(list(args), reverse=True)
for index in indexes:
del list_[index]
return list_
Se ejecuta en n log (n) time, lo que debería convertirla en la solución más rápida y correcta hasta el momento.
De hecho, puedo pensar en dos formas de hacerlo:
cortar la lista como (esto borra los elementos primero, tercero y octavo)
somelist = somelist [1: 2] + somelist [3: 7] + somelist [8:]
hacer eso en su lugar, pero uno a la vez:
somelist.pop (2) somelist.pop (0)
Eliminar el método provocará un gran desplazamiento de los elementos de la lista. Creo que es mejor hacer una copia:
...
new_list = []
for el in obj.my_list:
if condition_is_true(el):
new_list.append(el)
del obj.my_list
obj.my_list = new_list
...
Entonces, ¿esencialmente quieres eliminar múltiples elementos en una sola pasada? En ese caso, la posición del siguiente elemento para eliminar se verá compensada por la cantidad de elementos eliminados previamente.
Nuestro objetivo es eliminar todas las vocales, que están precalculadas para ser índices 1, 4 y 7. Tenga en cuenta que es importante que los índices to_delete estén en orden ascendente, de lo contrario no funcionará.
to_delete = [1, 4, 7]
target = list("hello world")
for offset, index in enumerate(to_delete):
index -= offset
del target[index]
Sería más complicado si quisieras eliminar los elementos en cualquier orden. OMI, ordenando para to_delete
podría ser más fácil que averiguar cuándo debería o no restar del index
.
Esto ha sido mencionado, pero de alguna manera nadie logró hacerlo bien.
En la solución O(n)
sería:
indices = {0, 2}
somelist = [i for j, i in enumerate(somelist) if j not in indices]
Esto está muy cerca de la versión de SilentGhost , pero agrega dos llaves.
Importarlo solo por este motivo puede ser excesivo, pero si de todos modos usa pandas
, la solución es simple y directa:
import pandas as pd
stuff = pd.Series([''a'',''b'',''a'',''c'',''a'',''d''])
less_stuff = stuff[stuff != ''a''] # define any condition here
# results [''b'',''c'',''d'']
Para generalizar el comentario de sth . La eliminación de elementos en cualquier clase, que implementa abc.MutableSequence , y en la list
en particular, se realiza a través del método mágico __delitem__
. Este método funciona de forma similar a __getitem__
, lo que significa que puede aceptar un número entero o una porción. Aquí hay un ejemplo:
class MyList(list):
def __delitem__(self, item):
if isinstance(item, slice):
for i in range(*item.indices(len(self))):
self[i] = ''null''
else:
self[item] = ''null''
l = MyList(range(10))
print(l)
del l[5:8]
print(l)
Esto producirá
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, ''null'', ''null'', ''null'', 8, 9]
Para los índices 0 y 2 de la lista A:
for x in (2,0): listA.pop(x)
Para algunos índices aleatorios para eliminar de listA:
indices=(5,3,2,7,0)
for x in sorted(indices)[::-1]: listA.pop(x)
Por alguna razón, no me gusta ninguna de las respuestas aquí. Sí, funcionan, pero estrictamente hablando, la mayoría de ellos no están eliminando elementos de una lista, ¿o sí? (Pero haciendo una copia y luego reemplazando la original con la copia editada).
¿Por qué no simplemente eliminar primero el índice más alto?
¿Hay alguna razón para esto? Solo lo haría:
for i in sorted(indices, reverse=True):
del somelist[i]
Si realmente no desea eliminar los elementos al revés, entonces supongo que debe desincorporar los valores de los índices que son mayores que el último índice eliminado (realmente no puede usar el mismo índice ya que tiene una lista diferente) o usar una copia de la lista (que no sería ''borrar'' sino reemplazar el original con una copia editada).
¿Me falta algo aquí, alguna razón para NO eliminar en el orden inverso?
Probablemente no sea la mejor solución para este problema:
indices = 0, 2
somelist = [i for j, i in enumerate(somelist) if j not in indices]
Puede usar numpy.delete
siguiente manera:
import numpy as np
a = [''a'', ''l'', 3.14, 42, ''u'']
I = [0, 2]
np.delete(a, I).tolist()
# Returns: [''l'', ''42'', ''u'']
Si no te importa terminar con una matriz numpy
al final, puedes omitir el .tolist()
. Debería ver algunas mejoras de velocidad bastante importantes, también, haciendo que esta sea una solución más escalable. No lo he comparado, pero numpy
operaciones numpy
son código compilado escrito en C o Fortran.
Puedes hacerlo de esa manera en un dict, no en una lista. En una lista, los elementos están en secuencia. En un dict dependen solo del índice.
Código simple solo para explicarlo haciendo :
>>> lst = [''a'',''b'',''c'']
>>> dct = {0: ''a'', 1: ''b'', 2:''c''}
>>> lst[0]
''a''
>>> dct[0]
''a''
>>> del lst[0]
>>> del dct[0]
>>> lst[0]
''b''
>>> dct[0]
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
dct[0]
KeyError: 0
>>> dct[1]
''b''
>>> lst[1]
''c''
Una forma de "convertir" una lista en un dict es:
>>> dct = {}
>>> for i in xrange(0,len(lst)): dct[i] = lst[i]
El inverso es:
lst = [dct[i] for i in sorted(dct.keys())]
De todos modos, creo que es mejor comenzar a eliminar del índice más alto como dijiste.
Puedes usar esta lógica:
my_list = [''word'',''yes'',''no'',''nice'']
c=[b for i,b in enumerate(my_list) if not i in (0,2,3)]
print c
Quería una manera de comparar las diferentes soluciones que hacían que sea fácil girar las perillas.
Primero genere mis datos:
import random
N = 16 * 1024
x = range(N)
random.shuffle(x)
y = random.sample(range(N), N / 10)
Luego definí mis funciones:
def list_set(value_list, index_list):
index_list = set(index_list)
result = [value for index, value in enumerate(value_list) if index not in index_list]
return result
def list_del(value_list, index_list):
for index in sorted(index_list, reverse=True):
del(value_list[index])
def list_pop(value_list, index_list):
for index in sorted(index_list, reverse=True):
value_list.pop(index)
Luego utilicé timeit
para comparar las soluciones:
import timeit
from collections import OrderedDict
M = 1000
setup = ''from __main__ import x, y, list_set, list_del, list_pop''
statement_dict = OrderedDict([
(''overhead'', ''a = x[:]''),
(''set'', ''a = x[:]; list_set(a, y)''),
(''del'', ''a = x[:]; list_del(a, y)''),
(''pop'', ''a = x[:]; list_pop(a, y)''),
])
overhead = None
result_dict = OrderedDict()
for name, statement in statement_dict.iteritems():
result = timeit.timeit(statement, number=M, setup=setup)
if overhead is None:
overhead = result
else:
result = result - overhead
result_dict[name] = result
for name, result in result_dict.iteritems():
print "%s = %7.3f" % (name, result)
Salida
set = 1.711
del = 3.450
pop = 3.618
Entonces el generador con los índices en un set
fue el ganador. Y del
es un poco más rápido que pop
.
Si está eliminando varios elementos no adyacentes, entonces lo que describe es la mejor manera (y sí, asegúrese de comenzar desde el índice más alto).
Si sus elementos son adyacentes, puede usar la sintaxis de asignación de división:
a[2:10] = []
Soy un principiante total en Python, y mi programación en este momento es tosca y sucia, por decir lo menos, pero mi solución fue utilizar una combinación de los comandos básicos que aprendí en los primeros tutoriales:
SomeList = [1,2,3,4,5,6,7,8,10]
Rem = [0,5,7]
for i in Rem:
SomeList[i]=''!'' # mark for deletion
for i in range(0,SomeList.count(''!'')):
SomeList.remove(''!'') # remove
print SomeList
Obviamente, debido a tener que elegir un carácter de "marcar para borrar", esto tiene sus limitaciones.
En cuanto al rendimiento a medida que aumenta el tamaño de la lista, estoy seguro de que mi solución no es óptima. Sin embargo, es sencillo, lo que espero atraiga a otros principiantes, y funcionará en casos simples donde SomeList es de un formato conocido, por ejemplo, siempre numérico ...
Un método alternativo de comprensión de listas que usa valores de índice de lista:
stuff = [''a'', ''b'', ''c'', ''d'', ''e'', ''f'', ''woof'']
index = [0, 3, 6]
new = [i for i in stuff if stuff.index(i) not in index]
Esto devuelve:
[''b'', ''c'', ''e'', ''f'']
aquí hay otro método que elimina los elementos en su lugar. también si su lista es realmente larga, es más rápida.
>>> a = range(10)
>>> remove = [0,4,5]
>>> from collections import deque
>>> deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)
>>> timeit.timeit(''[i for j, i in enumerate(a) if j not in remove]'', setup=''import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)'', number=1)
0.1704120635986328
>>> timeit.timeit(''deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)'', setup=''from collections import deque;import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)'', number=1)
0.004853963851928711
podemos hacer esto mediante el uso de un bucle for que itera sobre los índices después de ordenar la lista de índices en orden descendente
mylist=[66.25, 333, 1, 4, 6, 7, 8, 56, 8769, 65]
indexes = 4,6
indexes = sorted(indexes, reverse=True)
for i in index:
mylist.pop(i)
print mylist
técnicamente, la respuesta es NO, no es posible eliminar dos objetos AL MISMO TIEMPO. Sin embargo, es posible eliminar dos objetos en una línea de hermosa pitón.
del (foo[''bar''],foo[''baz''])
eliminará foo[''bar'']
recursiva, luego foo[''baz'']
l = [''a'',''b'',''a'',''c'',''a'',''d'']
to_remove = [1, 3]
[l[i] for i in range(0, len(l)) if i not in to_remove])
Es básicamente lo mismo que la respuesta más votado, solo una forma diferente de escribirlo. Tenga en cuenta que el uso de l.index () no es una buena idea, ya que no puede manejar elementos duplicados en una lista.
some_list.remove(some_list[max(i, j)])
Evita el costo de clasificación y tiene que copiar explícitamente la lista.