2

If I have a list like this:

MyList = [1,2,3,4,5,'hi', 6,7, 'hi', 8, 'hi', 9]

how can I remove all the items 'hi' from the list? I have tried the method remove() but it works only once:

MyList.remove('hi')
>>>> MyList
[1,2,3,4,5,6,7,'hi',8,'hi',9]

Yes, I could do something like this:

while 'hi' in MyList:
    MyList.remove('hi')

but does anyone know any more elegant way than iterating n-times the same instruction?

Matteo NNZ
  • 11,930
  • 12
  • 52
  • 89

4 Answers4

4

while 'hi' in MyList: MyList.remove('hi') is O(N**2), better use a simple list comprehension which does the same thing in O(N) time:

MyList = [item for item in MyList if item != 'hi']
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • Yeah I figured that out, that's why I wanted something different. Despite my very limited knowledge of Python, does not list comprehension iterate O(N**2) anyway? – Matteo NNZ Feb 12 '14 at 11:55
  • 1
    @MatteoNNZ No, a LC is `O(N)`, you're iterating over the list only once. – Ashwini Chaudhary Feb 12 '14 at 11:56
  • @Aswhini Chaudhary, true. I will use list comprehension then, thanks a lot. – Matteo NNZ Feb 12 '14 at 11:58
  • Unfortunately I cannot set two answers accepted, for sake of correctness I will accept Martjin's one cause it came slightly before and it's exactly the same. Thanks a lot for the solution and the explanation. – Matteo NNZ Feb 12 '14 at 12:04
3

Use a list comprehension:

MyList = [v for v in MyList if v != 'hi']

This rebuilds the list to only contain values not equal to 'hi'.

list.remove() calls must move the rest of the list items forward, using a list comprehension instead is more efficient.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
2

You can use filter function I guess. Here is docs: filter docs

MyList = [1,2,3,4,5,'hi', 6,7, 'hi', 8, 'hi', 9]

def f(item, element="hi"):
    if item == element:
        return False
    else:
        return True

print filter(f, MyList)
>>> [1, 2, 3, 4, 5, 6, 7, 8, 9]

Thanks to Tim Pietzcker for his improvement. The f function could be shorter

def f(item, element="hi"): return item != element
Nodari Lipartiya
  • 1,148
  • 3
  • 14
  • 24
0

You can also use generator expression:

NewList = (x for x in MyList if x != 'hi')

Then you can iterate this as NewList.next() until it raise StopIteration.

Manjunath
  • 150
  • 1
  • 6
  • "not x == 'hi'" instead of "x != 'hi'" ? I would suggest the latter. – Paddy3118 Feb 12 '14 at 12:50
  • @Paddy3118 Can you tell me the reason why shouldn't i use "not x == 'hi'" ? – Manjunath Feb 12 '14 at 12:58
  • 1
    Hi @Manjunath, It is purely a subjective stylistic issue. Do you say "This is False" or "This is not True"? In "not x == 'hi'" there are two tests to read: not and equal; in the second case of "x != 'hi'" just the one: not-equal. The second seems to more directly impart its meaning. – Paddy3118 Feb 12 '14 at 13:48
  • 1
    @Manjunath `!=` is clearly more readable, succinct than `not x == ...` and does the same thing in less byte code steps. And in case `x` was an instance of some user defined class then it would've called `__eq__` instead of `__ne__`, and note that it is not compulsory to have `__ne__` == `not __ne__` in user defined classes. – Ashwini Chaudhary Feb 12 '14 at 13:56
  • @Manjunath And this is applicable to `in` and `is` operator as well: `x not in foo` should be preferred over `not x in foo`, though these two compile to same byte code but internally Python's peephole optimizer actually converts the second expression to the first one. – Ashwini Chaudhary Feb 12 '14 at 13:59
  • * `__ne__ == not __eq__` – Ashwini Chaudhary Feb 12 '14 at 14:18