Reputation: 49013
Background
The algorithm manipulates financial analytics. There are multiple lists of the same size and they are filtered into other lists for analysis. I am doing the same filtering on different by parallel lists. I could set it up so that a1,b1,c2 occur as a tuple in a list but then the analytics have to stripe the tuples the other way to do analysis (regression of one list against the other, beta, etc.).
What I want to do
I want to generate two different lists based on a third list:
>>> a = list(range(10))
>>> b = list(range(10,20))
>>> c = list(i & 1 for i in range(10))
>>>
>>> aprime = [a1 for a1, c1 in zip(a,c) if c1 == 0]
>>> bprime = [b1 for b1, c1 in zip(b,c) if c1 == 0]
>>> aprime
[0, 2, 4, 6, 8]
>>> bprime
[10, 12, 14, 16, 18]
It seems there should be a pythonic/functional programming/itertools way to create the two lists and iterate over the three lists only once. Something like:
aprime, bprime = [a1, b1 for a1, b1, c1 in zip(a,b,c) if c1 == 0]
But of course this generates a syntax error.
The question
Is there a pythonic way?
Micro-optimization shootout
The ugly but pythonic-to-the-max one-liner edges out the "just use a for-loop" solution and my original code in the ever popular timeit cage match:
>>> import timeit
>>> timeit.timeit("z2(a,b,c)", "n=100;a = list(range(n)); b = list(range(10,10+n)); c = list(i & 1 for i in range(n));\ndef z2(a,b,c):\n\treturn zip(*[(a1,b1) for a1,b1,c1 in zip(a,b,c) if c1==0])\n")
26.977873025761482
>>> timeit.timeit("z2(a,b,c)", "n=100;a = list(range(n)); b = list(range(10,10+n)); c = list(i & 1 for i in range(n));\ndef z2(a,b,c):\n\taprime, bprime = [], [];\n\tfor a1, b1, c1 in zip(a, b, c):\n\t\tif c1 == 0:\n\t\t\taprime.append(a1); bprime.append(b1);\n\treturn aprime, bprime\n")
32.232914169258947
>>> timeit.timeit("z2(a,b,c)", "n=100;a = list(range(n)); b = list(range(10,10+n)); c = list(i & 1 for i in range(n));\ndef z2(a,b,c):\n\treturn [a1 for a1, c1 in zip(a,c) if c1 == 0], [b1 for b1, c1 in zip(b,c) if c1 == 0]\n")
32.37302275847901
Upvotes: 2
Views: 2982
Reputation: 370192
This might win the ugliest code award, but it works in one line:
aprime, bprime = zip(*[(a1,b1) for a1,b1,c1 in zip(a,b,c) if c1==0])
Upvotes: 5
Reputation: 4309
Just use a for
loop:
aprime = []
bprime = []
for a1, b1, c1 in zip(a, b, c):
if c1 == 0:
aprime.append(a1)
bprime.append(b1)
Upvotes: 4
Reputation: 2609
There's no way to create multiple lists at a time with list comprehensions--if you only want to iterate once you're going to need to do it some other way--possible with a loop.
You could use a list comprehension to create a list of tuples, with the first element belonging to one list, the second to the other. But if you do want them as separate lists, you're going to have to use another operation to split it, anyway.
Upvotes: 0