Deleting multiple elements from a list

Deleting multiple elements from a list

Is it possible to delete multiple elements from a list at the same time? If I want to delete elements at index 0 and 2, and try something like del somelist[0], followed by del somelist[2], the second statement will actually delete somelist[3].

I suppose I could always delete the higher numbered elements first but I'm hoping there is a better way.

Trouble with local variables in C#


Combining Dictionaries Of Lists In Python
Probably not the best solution for this problem:.
C# Multiple Generic List<t> - Combining Them? [duplicate]
indices = 0, 2 somelist = [i for j, i in enumerate(somelist) if j not in indices] 

How do I escape a foreach loop during last iteration?

Nhibernate - Getting a list


What's the most pythonic way to ensure that all elements of a list are different?
If you're deleting multiple non-adjacent items, then what you describe is the best way (and yes, be sure to start from the highest index)..
How to pick certain elements of x-tuple returned by a function?
If your items are adjacent, you can use the slice assignment syntax:.
How to check if permutations have equal parity?
a[2:10] = [] 


For some reason I don't like any of the answers here.

Yes, they work, but strictly speaking most of them aren't deleting elements in a list, are they? (But making a copy and then replacing the original one with the edited copy).. Why not just delete the higher index first?. Is there a reason for this? I would just do:.
for i in sorted(indices, reverse=True):     del somelist[i] 
If you really don't want to delete items backwards, then I guess you should just deincrement the indices values which are greater than the last deleted index (can't really use the same index since you're having a different list) or use a copy of the list (which wouldn't be 'deleting' but replacing the original with an edited copy).. Am I missing something here, any reason to NOT delete in the reverse order?.


As a specialisation of Greg's answer, you can even use extended slice syntax.


If you wanted to delete items 0 and 2:.
>>> a= [0, 1, 2, 3, 4] >>> del a[0:3:2] >>> a [1, 3, 4] 
This doesn't cover any arbitrary selection, of course, but it can certainly work for deleting any two items..


As a function:.
def multi_delete(list_, *args):     indexes = sorted(list(args), reverse=True)     for index in indexes:         del list_[index]     return list_ 
Runs in n log(n) time, which should make it the fastest correct solution yet..


So, you essentially want to delete multiple elements in one pass? In that case, the position of the next element to delete will be offset by however many were deleted previously.. Our goal is to delete all the vowels, which are precomputed to be indices 1, 4, and 7.

Note that its important the to_delete indices are in ascending order, otherwise it won't work..
to_delete = [1, 4, 7] target = list("hello world") for offset, index in enumerate(to_delete):   index -= offset   del target[index] 
It'd be a more complicated if you wanted to delete the elements in any order.

IMO, sorting to_delete might be easier than figuring out when you should or shouldn't subtract from index..


I'm a total beginner in Python, and my programming at the moment is crude and dirty to say the least, but my solution was to use a combination of the basic commands I learnt in early tutorials:.
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 
Obviously, because of having to choose a "mark-for-deletion" character, this has its limitations.

. As for the performance as the size of the list scales, I'm sure that my solution is sub-optimal.

However, it's straightforward, which I hope appeals to other beginners, and will work in simple cases where SomeList is of a well-known format, e.g., always numeric....


You can use numpy.delete as follows:.
import numpy as np a = ['a', 'l', 3.14, 42, 'u'] I = [0, 2] np.delete(a, I).tolist() # Returns: ['l', '42', 'u'] 
If you don't mind ending up with a numpy array at the end, you can leave out the .tolist().

You should see some pretty major speed improvements, too, making this a more scalable solution.

I haven't benchmarked it, but numpy operations are compiled code written in either C or Fortran..


here is another method which removes the elements in place.

also if your list is really long, it is faster..
>>> 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 


This has been mentioned, but somehow nobody managed to actually get it right.. On O(n) solution would be:.
indices = {0, 2} somelist = [i for j, i in enumerate(somelist) if j not in indices] 
This is really close to SilentGhost's version, but adds two braces..


Here is an alternative, that does not use enumerate() to create tuples (as in SilentGhost's original answer).. This seems more readable to me.

(Maybe I'd feel differently if I was in the habit of using enumerate.) CAVEAT: I have not tested performance of the two approaches..
# 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 ]
NOTE: Python 2.7 syntax.

For Python 3, xrange => range.. Usage:.
lst = [ 11*x for x in xrange(10) ] somelist = delete_by_indices( lst, [0, 4, 5]) 
[11, 22, 33, 66, 77, 88, 99] 
--- BONUS ---. Delete multiple values from a list.

That is, we have the values we want to delete:.
# 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 ]
somelist = delete__by_values( lst, [0, 44, 55] ) 
[11, 22, 33, 66, 77, 88, 99] 
This is the same answer as before, but this time we supplied the VALUES to be deleted [0, 44, 55]..


Remove method will causes a lot of shift of list elements.

I think is better to make a copy:.

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 ...


technically, the answer is NO it is not possible to delete two objects AT THE SAME TIME.

However, it IS possible to delete two objects in one line of beautiful python..
del (foo['bar'],foo['baz']) 
will recusrively delete foo['bar'], then foo['baz'].


we can do this by use of a for loop iterating over the indexes after sorting the index list in descending order.
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 


An alternative list comprehension method that uses list index values:.
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] 
This returns:.
['b', 'c', 'e', 'f'] 


I can actually think of two ways to do it:.
  1. slice the list like (this deletes the 1st,3rd and 8th elements). somelist = somelist[1:2]+somelist[3:7]+somelist[8:].
  2. do that in place, but one at a time:. somelist.pop(2) somelist.pop(0).


You can do that way on a dict, not on a list.

In a list elements are in sequence.

In a dict they depend only on the index.. Simple code just to explain it by doing:.
>>> 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' 
A way to "convert" a list in a dict is:.
>>> dct = {} >>> for i in xrange(0,len(lst)): dct[i] = lst[i] 
The inverse is:.
lst = [dct[i] for i in sorted(dct.keys())] 
Anyway I think it's better to start deleting from the higher index as you said..


For the indices 0 and 2 from listA:.
for x in (2,0): listA.pop(x) 
For some random indices to remove from listA: .
indices=(5,3,2,7,0)  for x in sorted(indices)[::-1]: listA.pop(x) 


To generalize the comment from @sth.

Item deletion in any class, that implements abc.MutableSequence, and in list in particular, is done via __delitem__ magic method.

This method works similar to __getitem__, meaning it can accept either an integer or a slice.

Here is an example:.
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) 
This will output.
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 'null', 'null', 'null', 8, 9] 


Importing it only for this reason might be overkill, but if you happen to be using pandas anyway, then the solution is simple and straightforward:.
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'] 

82 out of 100 based on 72 user ratings 1072 reviews