Created
April 17, 2019 16:59
-
-
Save IvanaGyro/9d4a26fe9f4691bec0cdf7a0928ee8ab to your computer and use it in GitHub Desktop.
An other implementation of built-in generator `itertools.combinations` in pure Python. This function is faster than the official demostration in some cases.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def combinations(iterable, r, start=0): | |
''' | |
A generator that yields the combinations of the iterable object. | |
This generator has the same interface as the built-in generator | |
`itertools.combinations`. This function is faster than the official | |
demostration when the r is closed to the half of length of the input | |
iterable object. | |
''' | |
pool = tuple(iterable) | |
l = len(pool) | |
if r == 0 or l - start < r: | |
return | |
for i in range(start, l): | |
if r == 1: | |
yield (pool[i], ) | |
else: | |
for res in combinations(pool, r - 1, i + 1): | |
yield (pool[i], ) + res | |
def offical_combinations(iterable, r): | |
''' | |
link: https://docs.python.org/zh-cn/3/library/itertools.html#itertools.combinations | |
''' | |
# combinations('ABCD', 2) --> AB AC AD BC BD CD | |
# combinations(range(4), 3) --> 012 013 023 123 | |
pool = tuple(iterable) | |
n = len(pool) | |
if r > n: | |
return | |
indices = list(range(r)) | |
yield tuple(pool[i] for i in indices) | |
while True: | |
for i in reversed(range(r)): | |
if indices[i] != i + n - r: | |
break | |
else: | |
return | |
indices[i] += 1 | |
for j in range(i+1, r): | |
indices[j] = indices[j-1] + 1 | |
yield tuple(pool[i] for i in indices) | |
task1 = \ | |
''' | |
for c in combinations({}, 7): | |
pass | |
''' | |
task2 = \ | |
''' | |
for c in offical_combinations({}, 7): | |
pass | |
''' | |
task3 = \ | |
''' | |
for c in itertools.combinations({}, 7): | |
pass | |
''' | |
a7 = [1, 2, 3, 4, 5, 6, 7] | |
a10 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | |
a13 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] | |
if __name__ == '__main__': | |
import timeit | |
print( | |
timeit.timeit(task1.format('a7'), 'from combinations import combinations, a7', number = 1000), | |
timeit.timeit(task2.format('a7'), 'from combinations import offical_combinations, a7', number = 1000), | |
timeit.timeit(task3.format('a7'), 'from combinations import a7; import itertools', number = 1000), | |
) | |
print() | |
print( | |
timeit.timeit(task1.format('a10'), 'from combinations import combinations, a10', number = 1000), | |
timeit.timeit(task2.format('a10'), 'from combinations import offical_combinations, a10', number = 1000), | |
timeit.timeit(task3.format('a10'), 'from combinations import a10; import itertools', number = 1000), | |
) | |
print() | |
print( | |
timeit.timeit(task1.format('a13'), 'from combinations import combinations, a13', number = 1000), | |
timeit.timeit(task2.format('a13'), 'from combinations import offical_combinations, a13', number = 1000), | |
timeit.timeit(task3.format('a13'), 'from combinations import a13; import itertools', number = 1000), | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment