2

Is it possible to do an action with the item in a list comprehension?

Example:

list = [1, 2, 3]
list_filtered = [ i for i in list if i == 3 AND DO SOMETHING WITH I]
print (list_filtered)

For example if I want to remove the '3' how would I go about it? Logic says that it's something like:

list = [1, 2, 3]
list_filtered = [ i for i in list if i == 3 && list.remove(i) ]
print (list_filtered)

I can't seem to make Python perform an action with that 'i' with any syntax that I tried. Can someone please elaborate?

EDIT: Sorry, the explanation might not be clear enough. I know how to iterate and create the new list. I want to create "list_filtered" and remove that value from "list" if it fits the "IF" statement.

Practically I need the following:

list = [1, 2, 3]
list_filtered = [ i for i in list if i == 3 && list.remove(i) ]
print (list_filtered)
# output >> [3]
print (list)
# output >> [1, 2]

I hope the above makes it more clear. Also, please note that my question is if this can be done in the list comprehension specifically. I know how to do it with additional code. :)

EDIT2: Apparently what I wanted to do isn't possible and also isn't advisable (which is the reason it isn't possible). It seemed like a logical thing that I just didn't know how to do. Thanks guys :)

Neekoy
  • 1,818
  • 17
  • 39
  • 8
    first of all this is not what list comprehension is for. List comprehension should not really have side effects, it should just create a list. Furthermore, you cannot modify container you are iterating over during iteration - no matter comprehension or not. – lejlot Oct 26 '16 at 22:37
  • What is it that you expect as a result here? What are the new values of list_filtered and list? – Prune Oct 26 '16 at 22:39
  • Hmm. Generally it sounds perfectly plausible to iterate through a list and remove the element you iterated through if it fits the "if" statement. Apparently this isn't possible with list comprehensions, which was my question. "Is this possible, and if so - how?". Thanks for the information :) – Neekoy Oct 26 '16 at 22:44

3 Answers3

4

If you're just trying to remove 3 you could do:

list_filtered=[i for i in list if i != 3]
print(list_filtered) # [1,2]

This will remove all values that are not equal to 3.

Alternatively if you wanted to do something like increment all the items in the list you would do:

[i+1 for i in list]
>>> [2,3,4]

Using a function on every item of the list would look like:

[float(i) for i in list]
>>> [1.0, 2.0, 3.0]

You can do ternary statements:

[i if i<3 else None for i in list]
>>>[1, 2, None]

and a whole lot more...

Here is more documentation on list comprehensions.

Given your new updates, I would try something like:

list_filtered=[list.pop(list.index(3))]

Then list_filtered would be [3] and list would be [1,2] as your specified.

Community
  • 1
  • 1
LMc
  • 5,865
  • 2
  • 12
  • 31
  • Sorry, the explanation might not be clear enough. I know how to iterate and create the new list. I want to create "list_filtered" and remove that value from "list" if it fits the "IF" statement. Practically the goal is to create a new list ("list_filtered"), and edit the existing one ("list") in the same list comprehension statement using "x". – Neekoy Oct 26 '16 at 22:50
  • @Neekoy if that's the case I'd stick with the advice from leaf. You'd want to go about that a different way – LMc Oct 26 '16 at 22:53
3

Your miss understand the purpose of list comprehension. List comprehension should be used to create a list, not to use its side effects. Further more, as Leijot has already mentioned, you should never modify a container while iterating over it.

If you want to filter out certain elements in a list using list comprehension, use an if statement:

>>> l = [1, 2, 3]
>>> l_filtered = [i for i in l if i != 3]
>>> l_filtered
[1, 2]
>>> 

Alternatively, you can use the builtin function filter():

>>> l = [1, 2, 3]
>>> l_filtered = list(filter(lambda x: x != 3, l))
>>> l_filtered
[1, 2]
>>>

Edit: Based on your most recent edit, what your asking is absolutely possible. Just use two different list comprehensions:

>>> l = [1, 2, 3]
>>> l_filtered = [i for i in l if i == 3]
>>> l_filtered
[3]
>>> l = [i for i in l if i != 3] # reassigning the value of l to a new list
>>> l
[1, 2]
>>>
Christian Dean
  • 19,561
  • 6
  • 42
  • 71
  • I'll mark this question as the correct one even though everyone gave the answer I was going for - it's not possible. I'm marking this one since it specifically says that the container shouldn't be modified while iterating. – Neekoy Oct 26 '16 at 22:56
  • @N thanks. But if you must change your original list, just reassign it to the value of the list comprehension. – Christian Dean Oct 26 '16 at 22:58
  • That's the thing, I want the original list to contain all values **except** those that are in the list_filtered. And I wanted to do that in the same list comparison function. – Neekoy Oct 26 '16 at 23:01
  • Yup, I'm aware I can do this with two separate list comparisons. I was looking to do it in a single one, which apparently isn't possible. :/ – Neekoy Oct 26 '16 at 23:15
  • @Neekoy as of now.. But I'll update my answer if I find anything ;) – Christian Dean Oct 26 '16 at 23:59
1

Maybe you want to provide a different example of what you're trying to do since you shouldn't remove elements from a list while you're iterating over it. Since list comprehensions create another list anyway, you could accomplish the same thing as your example by building a list that omits certain elements. If your goal is to create a list that excludes the value 3, to slightly modify your example:

l = [1, 2, 3]
list_filtered = [ i for i in l if i != 3 ]

l remains unaltered, but list_filtered now contains [1, 2].

beeftendon
  • 657
  • 6
  • 13
  • The purpose of my question is to create "list_filtered" and alter "list" in the same time. – Neekoy Oct 26 '16 at 22:48
  • @Neekoy So are the new list and the modified original list supposed to contain the same values? – beeftendon Oct 26 '16 at 22:56
  • I added an edit to the OP with two example outputs for the lists. I think it should make more sense that way. I'm with the impression this isn't possible though. – Neekoy Oct 26 '16 at 23:00