Please excuse the vagueness of my question, I don't have any formal training in CS. I'm pretty sure a solution already exists, but I can't find an answer because I don't know what question to ask.
Essentially, I'm looking for the name of an algorithm, or group of algorithms, to find all combinations of several lists where each list contains the possibilities for a single position. That is, some function that can perform the mapping:
((a,b,c), (1,2), (z,g,h), (7)) ->
((a,1,z,7), (a,1,g,7), (a,1,h,7), (a,2,z,7), ... (c,2,h,7))
such that the result can be used to iterate over all possible combinations of the per-position lists in order.
The number of lists is variable, and the size of each list is variable and independent of the other lists. All the example solutions are missing at least one of those criteria.
It would also be awesome if anyone knew of pseudocode or example implementations for any of those algorithms, or a Python package that can handle this.
I can and have solved the problem previously, but I would like to know if there are better solutions out there before I implement my design again.
Thanks for your time.
For those curious, my previous solution looked something like what is described in this paper, which is the only example solution I've found. However, it doesn't name the problem, nor does it give me a jumping off point for further research. Here is an (untested) Python listing of my general solution:
def nloop(*args):
lists = args
n = len(lists) # Number of lists
# Exit if no lists were passed
if n <= 0:
raise StopIteration
i = [0] * n # Current index of each list
l = [len(L) for L in lists] # Length of each list
# Exit if any list is zero-length
if min(l) <= 0:
raise StopIteration
while True:
# Create and yield a list using the current indices
yield tuple( lists[x][ i[x] ] for x in range(n) )
# Increment the indices for the next loop
# Move to the next item in the last list
i[-1] += 1
# Check the lists in reverse order to carry any
# indices that have wrapped
for x in reverse(list(range(n))):
if i[x] >= l[x]:
i[x] = 0
if x > 0:
i[x-1] += 1
# If the first list has wrapped, we're done
if i[0] >= l[0]:
break
raise StopIteration
You are looking for itertools.product. It is equivalent to the nested for loop of arbitrary depth that you describe.
For your particular example (with appropriate syntactic modifications):
>>> from itertools import product
>>> list(product(('a', 'b', 'c'), (1, 2), ('z', 'g', 'h'), (7,)))
[('a', 1, 'z', 7),
('a', 1, 'g', 7),
('a', 1, 'h', 7),
('a', 2, 'z', 7),
('a', 2, 'g', 7),
('a', 2, 'h', 7),
('b', 1, 'z', 7),
('b', 1, 'g', 7),
('b', 1, 'h', 7),
('b', 2, 'z', 7),
('b', 2, 'g', 7),
('b', 2, 'h', 7),
('c', 1, 'z', 7),
('c', 1, 'g', 7),
('c', 1, 'h', 7),
('c', 2, 'z', 7),
('c', 2, 'g', 7),
('c', 2, 'h', 7)]
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