Finally, after a lot of head-banging, I found a way to avoid calling ord()
, which, apparently, is very expensive. Below is the test code and results:
from timeit import timeit
from itertools import count
from string import ascii_lowercase
def alphabet_position_Headcrab(text):
nums = [str(ord(x) - 96) for x in text.lower() if x >= 'a' and x <= 'z']
return " ".join(nums)
def alphabet_position_wvxvw(text):
result, i = [32, 32, 32] * len(text), 0
for c in bytes(text.lower(), 'ascii'):
if 97 <= c < 106:
result[i] = c - 48
i += 2
elif 106 <= c < 116:
result[i] = 49
result[i + 1] = c - 58
i += 3
elif 116 <= c <= 122:
result[i] = 50
result[i + 1] = c - 68
i += 3
return bytes(result[:i-1])
def letter_indexes(text):
text = text.lower()
letter_mapping = dict(zip(ascii_lowercase, count(1)))
indexes = [
letter_mapping[letter] for letter in text
if letter in letter_mapping
]
return ' '.join(str(index) for index in indexes)
def test(f):
data = "The sunset sets at twelve o' clock."
for _ in range(5):
f(data)
data = data + data
def speed_compare():
results = {
'wvxvw': timeit(
'test(alphabet_position_wvxvw)',
setup='from __main__ import (test, alphabet_position_wvxvw)',
number=10000,
),
'Headcrab': timeit(
'test(alphabet_position_Headcrab)',
setup='from __main__ import (test, alphabet_position_Headcrab)',
number=10000,
),
'MrGrj': timeit(
'test(letter_indexes)',
setup=(
'from __main__ import (test, letter_indexes)\n'
'from itertools import count\n'
'from string import ascii_lowercase\n'
),
number=10000,
)
}
for k, v in results.items():
print(k, 'scored', v)
Running speed_compare()
gives this output:
wvxvw scored 1.7537127458490431
Headcrab scored 2.346936965826899
MrGrj scored 2.2078608609735966