I have tested the following methods:
import random import string def checkWord1(word): r1 = 'qwertyuiop' r2 = 'asdfghjkl' r3 = 'zxcvbnm' row = 0 for idx, ch in enumerate(word): if idx == 0: row = 1 if ch in r1 else 2 if ch in r2 else 3 continue coming_row = 1 if ch in r1 else 2 if ch in r2 else 3 if row != coming_row: return False return True def checkWord2(word): r1 = 'qwertyuiop' r2 = 'asdfghjkl' r3 = 'zxcvbnm' return set(word).issubset(r1) or set(word).issubset(r2) or set(word).issubset(r3) def checkWord3(word): r1 = 'qwertyuiop' r2 = 'asdfghjkl' r3 = 'zxcvbnm' r = set(word) return r.issubset(r1) or r.issubset(r2) or r.issubset(r3) def checkWord4(word): r1 = set('qwertyuiop') r2 = set('asdfghjkl') r3 = set('zxcvbnm') row = 0 for idx, ch in enumerate(word): if idx == 0: row = 1 if ch in r1 else 2 if ch in r2 else 3 continue coming_row = 1 if ch in r1 else 2 if ch in r2 else 3 if row != coming_row: return False return True
And measure execution time:
word = ''.join(random.choice(string.ascii_lowercase) for _ in range(random.randint(0, 9))) print("One:") %timeit -n 10000 checkWord1(word) print("Two:") %timeit -n 10000 checkWord2(word) print("Three:") %timeit -n 10000 checkWord3(word) print("Four:") %timeit -n 10000 checkWord4(word)
Get results:
One: 475 ns ± 88.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) Two: 708 ns ± 117 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) Three: 552 ns ± 19.6 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) Four: 1.19 µs ± 10.8 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Although with different randomly generated string, the results are similar.
One is fastest, Three is faster and more stable than Two, Four is worst.
The reason I think why One is fastest is that
issubset(object) actually implicitly convert object to a set. That is costly.
This comparison is unfair. Suppose we have one word "qsdfwe", in method One, it will be check if in r1, and in the following loop, if it is found not a sub set of r1, there is also no possibility that it can be a sub set of others.
So I implement a even faster method, I think we can just focus on one row which is decided by the first char as these three rows are exclusive so that we do not check others any more.
def checkWord5(word): r = ['qwertyuiop', 'asdfghjkl', 'zxcvbnm'] first_char = word[0] row = r[0] if first_char in r[0] else r[1] if first_char in r[1] else r[2] for ch in word[1:]: if ch not in row: return False return True
Get results:
One: 728 ns ± 236 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) Two: 2.08 µs ± 55.8 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) Three: 1.43 µs ± 60 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) Four: 1.45 µs ± 7.74 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) Five: 374 ns ± 7.01 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)