In Python 3.4.2, is there a way to have an "if ... or ..." statement in a list comprehension?
Example:
filtered_list = [x for x in other_list
if not ' ' in x or ' ' in other_list[int(other_list.index(x) -1)]]
#^item just before "x" in "other_list"
I know this command doesn't work. I know this one doesn't either:
filtered_list = [x for x in other_list
if not (' ' in x) or (' ' in other_list[int(other_list.index(x) -1)])]
#^item just before "x" in "other_list"
Is there a way to do this? A "for" loop would be way easier to read, but I'm trying to push my understanding of list comprehensions. Thanks in advance.
(Oddly enough, I can't find a previous question like this on stackoverflow.)
Your code does do exactly what you're telling it to do (in simple cases):
>>> other_list = ['foo', 'bar ', 'baz ']
>>> filtered_list = [x for x in other_list
... if not ' ' in x or ' ' in other_list[int(other_list.index(x) -1)]]
>>> print filtered_list
['foo', 'baz ']
i.e, it picks all items that either don't contain four spaces, or follow an item that does contain four spaces.
It's really weird code in many ways -- for example, why use .index
which will pick the first item equal to x
in case of duplicates; and, should the first item be considered to "follow" the last one as this code is saying? But, without a clear explanation in English of what your code is supposed to accomplish, just "reverse engineering" the code as written, it does appear to do exactly what it says in simple cases (first item does not contain four spaces, no duplicates), although very, very inefficiently (O(N squared) where it's trivially simple to make it O(N) with enumerate
).
So please supply a clear, exhaustive explanation of what you think you're doing here, and I'll gladly edit this answer to show you how to do what you actually mean, rather than what you (apparently wrongly) coded. But, I can't read your mind, so... (BTW, this does need to be "an answer" since formatting the code above is crucial to its readability, so it can't be "just a comment").
Added: the normal way to "get the item just before the current one in other_list
" would of course not use .index
(which is O(N)
so makes the whole list comprehension O(N squared)
!) but rather enumerate
. What is "the item just before" the first one requires interpretation, but the normal reading is "there is no such thing".
So suppose you have two functions curp
(predicate qualifying the current item, if truthy on it) and prevp
(predicate qualifying the current item, if truthy on the previous item if any). Then, the normal way to pick items from list xs
would clearly be:
[x for i, x in enumerate(xs) if curp(x) or i>0 and prevp(xs[i-1])]
Of course it works exactly the same way whether the predicates are elegantly encapsulated into functions, as above, or more roughly expressed in-line. So if, e.g:
def curp(x): return 'AB' not in x
def prevp(xp): return 'CD' in xp
then the following listcomp is equivalent to the previous one, just less readable:
[x for i, x in enumerate(xs) if 'AB' not in X or i>0 and 'CD' in xs[i-1]]
Parentheses would be rather redundant here, and not 'AB' in X
an even less elegant, readable, and unambiguous way to express 'AB' not in X
-- but, feel free to ignore these style opinions, they only come from 15 years' worth of Python experience, after all:-)
You can use multiple and
s/or
s but only one if
. As an example, the following:
In [7]: a = [1,2,3,4,5,6,7,8,9,10]
In [8]: b = [x for x in a if x % 2 == 0 or x % 3 == 0]
In [9]: b
Out[9]: [2, 3, 4, 6, 8, 9, 10]
works just fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With