Created
May 12, 2019 02:14
-
-
Save NickBeeuwsaert/fb01328390b923069bda5322f8d68b5f to your computer and use it in GitHub Desktop.
Cartesian Product
This file contains 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
function* cartesianProduct(...iterables) { | |
const pools = iterables.map(function(iterable) { | |
const pool = Array.from(iterable); | |
return {pool, length: pool.length, counter: 0}; | |
}); | |
let iterations = pools.reduce( | |
(total, {length}) => total * length, | |
1 | |
); | |
while(iterations--) { | |
yield pools.map(({counter, pool}) => pool[counter]); | |
for(const pool of pools) { | |
pool.counter++; | |
if(pool.counter < pool.length) { | |
break; | |
} | |
pool.counter = 0; | |
} | |
} | |
} |
This file contains 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
import functools | |
import itertools | |
import operator | |
import pytest | |
def product(*iterables): | |
pools = [tuple(iterable) for iterable in iterables] | |
iterations = functools.reduce(operator.mul, map(len, pools)) | |
for i in range(iterations): | |
result = [] | |
for pool in pools: | |
result.append(pool[i % len(pool)]) | |
i //= len(pool) | |
yield tuple(result) | |
class CartesianProduct: | |
def __init__(self, *iterables): | |
self.pools = [tuple(iterable) for iterable in iterables] | |
def __len__(self): | |
return functools.reduce( | |
operator.mul, | |
map(len, self.pools) | |
) | |
def __getitem__(self, idx): | |
result = [] | |
for pool in self.pools: | |
result.append(pool[idx % len(pool)]) | |
idx = idx // len(pool) | |
return tuple(result) | |
def __iter__(self): | |
for i in range(len(self)): | |
yield self[i] | |
@pytest.mark.parametrize('a', [ | |
([1, 2], [3, 4]), | |
([1], [2]), | |
([1, 2, 3], [1, 2]), | |
([1, 2], [3, 4], [5, 6]), | |
([1], [2, 3], [4, 5, 6], [7, 8, 9, 10]), | |
([1, 2, 3, 4], [5, 6, 7], [8, 9], [10]), | |
]) | |
def test_product(a): | |
assert sorted(itertools.product(*a)) == sorted(product(*a)) | |
@pytest.mark.parametrize('a', [ | |
([1, 2], [3, 4]), | |
([1], [2]), | |
([1, 2, 3], [1, 2]), | |
([1, 2], [3, 4], [5, 6]), | |
([1], [2, 3], [4, 5, 6], [7, 8, 9, 10]), | |
([1, 2, 3, 4], [5, 6, 7], [8, 9], [10]), | |
]) | |
def test_cartesianproduct(a): | |
cart_prod = CartesianProduct(*a) | |
assert sorted(itertools.product(*a)) == sorted(cart_prod) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment