I create a cartesian product using the itertools.product
function:
from itertools import product
a = list(map(list, itertools.product(list(range(2)), repeat=3)))
Output:
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
Then I get rid of mirrors reflections in the following way:
b = []
for k, v in enumerate(a):
if v[::-1] not in a[:k]:
b.append(v[::-1])
Output:
[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 1], [1, 1, 1]]
But can I get the same effect step by step without saving all the results of itertools.product
in the list? For example, with the usual approach on the for loop:
for i in list(map(list, itertools.product(list(range(2)), repeat=3))):
# blah blah blah
Because ultimately I will use large cartesian products, at least repeat = 18
. And that is why I have to give up the approach on the lists. Unless there is another way to do it? I will be grateful for any tips.
import itertools
l = (list(i) for i in itertools.product(tuple(range(2)), repeat=3) if tuple(reversed(i)) >= tuple(i))
print list(l)
Output:
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 1], [1, 1, 1]]
Here is an idea for a recursive algorithm to generate only the necessary combinations (as opposed to generate the whole Cartesian product and discarding the unnecessary ones):
def noReflections(n, k, current=None, idx=0, symmetric=True):
# n: number of distinct elements
# k: sequences length
# current: sequence being generated
# idx: current generated index
# symmetric: true if the chosen elements up to now are symmetric
assert n >= 0 and k >= 0
if n == 0 or k == 0:
return
if idx == 0:
current = k * [0]
if idx < k // 2:
# Choose the value for current position (idx) and symmetric (idx2)
idx2 = k - idx - 1
for i in range(n):
# Value for current position
current[idx] = i
# If all previously selected values were symmetric,
# the symmetric position must have a value equal or greater
# than the current; otherwise it can take any value.
first = i if symmetric else 0
for j in range(first, n):
# Value for symmetric position
current[idx2] = j
# Recursive call
# Only keep symmetric flag if previously selected values
# and the ones selected now are symmetric.
yield from noReflections(n, k, current, idx + 1, symmetric and (i == j))
elif idx == k // 2 and (k % 2 == 1):
# In middle position of odd-length sequence
# Make one sequence with each possible value
for i in range(n):
current[idx] = i
yield tuple(current)
else:
# Even-length sequence completed
yield tuple(current)
print(list(noReflections(2, 3)))
>>> [(0, 0, 0), (0, 1, 0), (0, 0, 1), (0, 1, 1), (1, 0, 1), (1, 1, 1)]
I'm not sure this should perform better than the other answer though, because of the recursion and so on (in a couple of quick tests bot performed similarly in my machine).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With