How to change python collections by filtering in place?

I was wondering if in Python there is a way to modify collections without creating new ones. For example:.

lst = [1, 2, 3, 4, 5, 6] new_lst = [i for i in lst if i > 3] 

Works fine, but a new collection is being created. Is there a reason that Python collections lack a filter() method (or similar) that will modify the collection object in place?

+8
python collections
source share
6 answers

Other answers are correct; if you want all the names pointing to the old list to point to the new list, you can use the slice assignment.

However, this is not a true creature in place; a new list is first created elsewhere. The link in Sven’s answer is good.

The reason that it really doesn't work in place is that when creating a new list, such as O (n), each true deletion of a place in place can be O (k) in itself, where k is the length of the list from the point removal. The only way to avoid this with Python lists is to use some temporary storage that you do using slice assignment.

An example of an O (n) filter in place in collections.deque if you don't need to store your data in list :

 from collections import deque def dequefilter(deck, condition): for _ in xrange(len(deck)): item = deck.popleft() if condition(item): deck.append(item) deck = deque((1, 2, 3, 4, 5)) dequefilter(deck, lambda x: x > 2) # or operator.gt(2) print deck # deque([3, 4, 5]) 
+7
source share

If you want to do it locally, just use

 lst[:] = [i for i in lst if i > 3] 

This one will not be faster or save any memory , but it changes the object in place, if that is the semantics you need.

+17
source share

The solution lst[:] from @Sven Marnach is one option. You can also perform this operation in place using permanent additional memory using

 >>> i = 0 >>> while i < len(lst): ... if lst[i] <= 3: ... del lst[i] ... else: ... i += 1 ... >>> lst [4, 5, 6] 

... but this solution is not very readable and takes quadratic time due to the involvement of all the elements.

+1
source share

Correction of the original @larsmans solution , you can either do

 i = 0 while i < len(lst): if lst[i] <= 3: del lst[i] else i += 1 

or

 i = len(lst) while i > 0: if lst[i-1] <= 3: del lst[i-1] i -= 1 

The reason is the "index shift" that occurs with del . If I del in the ceratin index, I have to revise this index, because now it has a different meaning.

+1
source share

Because he is not needed .

 lst[:] = [i for i in lst if i > 3] 
0
source share

I think this is a transformation in place;

 lst = [1,2,3,4,5,6,7,8,9,10,11] to_exclude = [8,4,11,9] print 'lst == %s\nto_exclude == %s' % (lst,to_exclude) for i in xrange(len(lst)-1,-1,-1): if lst[i] in to_exclude: lst.pop(i) print '\nlst ==',lst 

result

 lst == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] to_exclude == [8, 4, 11, 9] lst == [1, 2, 3, 5, 6, 7, 10] 
0
source share

All Articles