Removing None objects from a sequence
Terry Reedy
tjreedy at udel.edu
Fri Dec 12 19:02:24 EST 2008
Tim Chase wrote:
>> If you want to literally remove None objects from a list....(or
>> mutable sequence)
>>
>> def deNone(alist):
>> n=len(alist)
>> i=j=0
>> while i < n:
>> if alist[i] is not None:
>> alist[j] = alist[i]
>> j += 1
>> i += 1
>> alist[j:i] = []
>>
>> blist=[None,1,None,2,None,3,None,None,4,None]
>> deNone(blist)
>> print(blist)
>>
>> # prints [1, 2, 3, 4]
>
> ...wouldn't a cleaner way of doing this just be
>
> >>> blist=[None,1,None,2,None,3,None,None,4,None]
No, making a filtered copy that is then copied back before being deleted
is algorithmically much messier. My code does the minimum work
necessary and is algorithmically cleaner.
> >>> alist = blist
> >>> blist[:] = [x for x in blist if x is not None]
> >>> blist
> [1, 2, 3, 4]
> >>> alist
> [1, 2, 3, 4]
>
> By using the slice assignment, it leaves the blist referring to the same
> list-object (as shown by the "alist" bit), and modifying it in place.
> This reads a lot more cleanly in my estimation.
>
> If the data-set is large, in 2.5+, you can just use a generator:
>
> blist[:] = (x for x in blist if x is not None)
Given that this works, that the setup for slice assignment does not mess
up the co-routine iteration over the same loop, this is pretty good. It
amounts to deNone with the i-j loop separated into an i loop and a j
loop in source and consumer co-routines. One could argue that that is
even better, even if written out as
def deNone2(alist):
src = (item for item in alist if item is not None)
j=0
try:
while True:
alist[j] = next(src)
j += 1
except StopIteration:
pass
alist[j:] = []
tjr
More information about the Python-list
mailing list