2

I want to delete the empty sub list, some ways are failed, but other ways are successful. Why ? The worry way:

data=[[],[],[],[],[]]
for rows in data:
    if len(rows)==0:
       list.remove(rows)
print data

the result is [[],[]].It isn't my expected result []

the correct way(my friend tell me,thank him):

list = [[],[],[],[],[]]
a=list(filter(lambda x: [] != x, list))
print a

the result is my expected empty list []

Alexander
  • 4,153
  • 1
  • 24
  • 37
M.Mark
  • 63
  • 2
  • 13
  • 2
    it is because you are iterating through a list that changes size. I am surprised that you don't get an error with the first code – Whitefret May 09 '16 at 07:43
  • Whitefret is correct. It's generally a bad idea to iterate over a list whilst you're deleting items from it. – davo36 May 09 '16 at 07:45
  • @Whitefret python's list iterator is basically an increasing index until IndexError is raised. That also explains the observed result and why no error is raised. Doesn't mean one should rely on this behaviour though... – Ilja Everilä May 09 '16 at 07:50
  • @IljaEverilä thanks for the precision ! – Whitefret May 09 '16 at 07:53

2 Answers2

3

Avoid iterating over a list while doing the changes on it:

data=[[],[],[],[],[]]
for rows in data:
    if len(rows)==0:
       data.remove(rows)
print data

Instead, create a new list:

>>> lst = []
>>> data = [[],[],[],[1,2,3]]
>>> 
>>> for rows in data:
        if rows: #if rows is not an empty list
            lst.append(rows)


>>> lst
[[1, 2, 3]]
>>> 

Same as you did with filter which creates a new object:

>>> lst = [[],[],[],[1,2,3],[1,],[], [4,5,6],[7]]
>>> lst = filter(list.__len__,lst)
>>> lst
[[1, 2, 3], [1], [4, 5, 6], [7]]

EDIT:

After doing some profiling, I got the following resutls:

>>> import timeit
>>> timeit.timeit('filter(list.__len__, lst)', setup='lst=[[],[],[],[1,2,3],[1,],[], [4,5,6],[7]]', number=1000000)
1.03789886128774
>>>
>>> timeit.timeit('filter(lambda x:x, lst)', setup='lst=[[],[],[],[1,2,3],[1,],[], [4,5,6],[7]]', number=1000000)
1.0035609489573218
>>>
>>> timeit.timeit('filter(None, lst)', setup='lst=[[],[],[],[1,2,3],[1,],[], [4,5,6],[7]]', number=1000000)
0.4335933814062045
>>>
>>> timeit.timeit('[l for l in lst if l]', setup='lst=[[],[],[],[1,2,3],[1,],[], [4,5,6],[7]]', number=1000000)
0.41073885410420985
Iron Fist
  • 10,739
  • 2
  • 18
  • 34
2
>>> data=[[],[],[],[],[]]
>>> filter(lambda x:x,data)
[]

>>> data=[[],[],[],[],[1]] 
>>> filter(lambda x:x,data)
[[1]]
bian
  • 1,456
  • 8
  • 7
  • Instead of `lambda x:x` you can also pass `None` as first parameter to the `filter` builtin function to achieve the same i.e. elements that equal `False` if converted to boolean (like None, 0, False, empty collections, empty strings, ...) get filtered out. – Byte Commander May 09 '16 at 10:36
  • thank you. exists this problem, change to `filter(lambda x:len(x), data)` – bian May 09 '16 at 12:15