4

Currently I have 2 lists which I divide by each other

a = [5,6,7,8]
b = [100,200,300,400]
output = [b/m for b,m in zip(a,b)]

However due to the nature of my database it is faster to retrieve list a and b differently:

data = [5,100,6,200,7,300,8,400]

The first value in the list is the first value in a, the second value the first value in b, the third value the second value in a and so on.

output = [5/100,6/200,7/300,8/400]

Thus I need to divide the first value by the second and the third by the fourth and so on. Now this is no problem, but I need it to be as fast as possible. Any suggestions?

Jens de Bruijn
  • 939
  • 9
  • 25

3 Answers3

5

You can use slicing for this:

output = [b / m for b, m in zip(data[::2], data[1::2])]

Edit 3: What we have now (len(data) = 8000):

  1. The iter solution by Jon Clements with ~1ms
  2. The normal slicing solution with 1.1ms
  3. The range solution with 2.5ms
  4. The map solution (materialising it using list) with 2.7ms
filmor
  • 30,840
  • 6
  • 50
  • 48
0
>>> data = [5,100,6,200,7,300,8,400]
>>> [data[i]/float(data[i+1]) for i in range(0,len(data),2)]
[0.05, 0.03, 0.023333333333333334, 0.02]

for i in range(0,len(data),2) generates 0,2,4,6. Thus data[i]/data[i+1] gives data[0]/data[1],...,data[6]/data[7]

Irshad Bhat
  • 8,479
  • 1
  • 26
  • 36
  • The question is explicitly on Python 3 which implies that `a / b` is `float` even for `a` and `b` integers. – filmor Dec 15 '14 at 17:31
  • Also (as expected due to the random access) this is by a factor of 5 slower on my machine than the slicing approach. Dropping the explicit `float` conversion leads to a factor of 2.4. – filmor Dec 15 '14 at 17:32
  • Oh! i didn't see the `python-3` tag. Updated my solution. – Irshad Bhat Dec 15 '14 at 17:36
0

I prefer to do this sort of thing with zip and map so that it can be accomplished in one line:

map(lambda x : x[0]/x[1], zip(a,b))

zip is a function that makes a list of tuples, like so:

>>>>zip(a,b)
[(5, 100), (6, 200), (7, 300), (8, 400)]

And map returns a new list that applies the given function to the whole row. I'm seeing other people report that this takes milliseconds. Applying this to your problem and using the list slicing given above in IPython:

%timeit map(lambda x : x[0]/x[1], zip(data[::2], data[1::2]))
1000000 loops, best of 3: 1.33 µs per loop

EDIT: with len(data) = 10000, I got 849 microseconds; with 8000, I get 685 microseconds.

SmearingMap
  • 320
  • 1
  • 11
  • In python 3.x - as this is tagged - it'd be instant... the OP would need to materialise to a list - anyway, instead of using the `lambda`, you're better off using `map(operator.div, ...)` (also - comparing your timeit with another post's timeit is somewhat apples and pears, as you're presumably not using the same hardware with the same work balance at the same time etc...) – Jon Clements Dec 15 '14 at 18:39
  • I also suspect that the 1.33us is because you've got iPython using 3.x (while your `map` example implies 2.x) and it's generating a generator (very, very quick), rather than materialising anything... hence the test is only the speed of generating the generator... not producing any results – Jon Clements Dec 15 '14 at 18:45