Based on a simple list comprehension :
yay = [ i for i in a if a[i] ]
nay = [ i for i in a if not a[i] ]
I am wondering if there is a way to assign both the yay and nay values at once ( ie hits and misses on the conditional )?
Something that would look like this
( yay , nay ) = ...
I was curious about this on readability and speed ( I was a bit surprised to see two list comprehensions are about 5% faster than a single for-loop that appends to either list )
update:
The original example was to grab a listing of "true" and "false" valued keys in a dict...
a = {i: i >= 50 for i in range(100)}
yay = [k for k, v in a.items() if v]
nay = [k for k, v in a.items() if not v]
The usual solution here is not to get all hung up on the idea of using a list comprehension. Just use a for loop:
yay, nay = [], []
for i in a:
if somecondition(i):
yay.append(i)
else:
nay.append(i)
If you find yourself doing this a lot then simply move the code out into a function:
def yesno(seq, cond):
yay, nay = [], []
for i in seq:
if cond(i):
yay.append(i)
else:
nay.append(i)
return yay, nay
yay, nay = yesno(a, lambda x: a[x])
The comments suggest this is slower than list comprehension. Passing the condition as a lambda is inevitably going to have a big hit and I don't think you can do much about that, but some of the performance hit probably comes from looking up the append method and that can be improved:
def yesno(seq, cond):
yay, nay = [], []
yes, no = yay.append, nay.append
for i in seq:
if cond(i):
yes(i)
else:
no(i)
return yay, nay
I don't know if that makes much of a difference, but it might be interesting to time it.
In the comments @martineau suggests using a generator and consuming it with any(). I'll include that here, but I would replace any with the itertools recipe to consume an iterator:
def consume(iterator, n):
"Advance the iterator n-steps ahead. If n is none, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
and then you can write:
yay, nay = [], []
consume((yay if a[i] else nay).append(i) for i in a)
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