1

Learning to be pythonic in 2.7. Is there a way to avoid the explicit loop? answer = [5, 4, 4, 3, 3, 2]

import numpy as np
import scipy.special as spe

nmax = 5     # n = 0, 1 ...5
mmax = 7     # m = 1, 2 ...7
big = 15.
z = np.zeros((nmax+1, mmax))
for i in range(nmax+1):
    z[i] = spe.jn_zeros(i, mmax)
answer = [np.max(np.where(z[i]<big))+1 for i in range(nmax+1)]
print answer # list of the largest m for each n where the mth zero of Jn < big
smci
  • 32,567
  • 20
  • 113
  • 146
uhoh
  • 3,713
  • 6
  • 42
  • 95
  • @twasbrillig caught an error, have included correction nmax -> nmax+1, I've then removed the +1 from mmax where it was incorrectly applied. – uhoh Nov 15 '14 at 08:39
  • ...and I added clarifications. n=0 refers to J0, etc. and remember the first zero is not the one at the origin (for n>0). – uhoh Nov 15 '14 at 08:53

1 Answers1

5

What does "more Pythonic" really mean here. One of the core tenets of Python is readability, so if there is no real performance reason to get rid of the loops, just keep them.

If you really wanted to see some other ways to do the same thing, then:

z = np.zeros((nmax+1, mmax))
for i in range(nmax+1):
    z[i] = spe.jn_zeros(i, mmax)

could be replaced with:

func = lambda i:spe.jn_zeros(i,mmax)
np.vstack(np.vectorize(func, otypes=[np.ndarray])(np.arange(nmax+1)))

which is slightly faster (1.35 ms vs. 1.77 ms) but probably less Pythonic and

[np.max(np.where(z[i]<big))+1 for i in range(nmax+1)]

could be replaced by

np.cumsum(z < big,axis=1)[:,-1]

which I would argue is more Pythonic (or numpythonic) and much faster (20 us vs. 212 us).

ebarr
  • 7,704
  • 1
  • 29
  • 40
  • 1
    Thanks for your answer @ebarr. Going from float to bool to integer in a dozen characters is pretty cool! (reminder to self: this takes advantage of jn_zeros being monotonic) – uhoh Nov 15 '14 at 11:49