Note that your approach can be improved quite a bit:
- The whole
is_vowel()
can be rewritten in one line (and considering also the case):
def is_vowel(c):
return c in 'aeiouAEIOU'
and that can be easily inlined.
- Instead of using
str.index()
, you can just keep track of the index at each iteration. The idiomatic way in Python is by using enumerate()
.
- If you do not want your function to return
None
, you have to explicitly use return
after your loop to handle the case of no character actually being a vowel.
- The code can be made more general by inputing the "vowel" definition as a paremeter.
Putting all these together, one gets:
def find_any(s, chars='aeiouAEIOU'):
for i, c in enumerate(s):
if c in chars:
return i
return -1
For larger input strings, and small character sets a much more efficient approach is to use the start
and stop
parameters of str.index()
or, possibly faster, str.find()
which does not require a try
/catch
to handle missing matches:
def find_any_other(s, chars='aeiouAEIOU'):
result = -1
for char in chars:
idx = s.find(char, 0, result)
if idx > 0:
result = idx
if not idx:
break
return result if result < len(s) else -1
A simple test to show the timings indicate that the second approach can be much faster:
n = 1
s = 'x' * n + 'hello'
%timeit find_any(s)
# 1.35 µs ± 174 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit find_any_other(s)
# 6.04 µs ± 332 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
n = 1000000
s = 'x' * n + 'hello'
%timeit find_any(s)
# 172 ms ± 6.18 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit find_any_other(s)
# 790 µs ± 36.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)