Reputation: 3
I'm trying to write a function that will take as input length L
and distance D
(both integers > 1
) and output all possible sequences that fit the following parameters:
1
L
elements 1
to D
between each element and the following elementSo, for L = 4
and D = 2
, the possible sequences would be:
1 2 3 4 (distance of 1 between each consecutive element)
1 2 3 5
1 2 4 5
1 2 4 6
1 3 4 5
1 3 4 6
1 3 5 6
1 3 5 7 (distance of 2 between each consecutive element)
Or, for L = 3
and D = 3
, the possible sequences would be:
1 2 3 (distance of 1 between each consecutive element)
1 2 4
1 2 5
1 3 4
1 3 5 (distance of 2 between each consecutive element)
1 3 6
1 4 5
1 4 6
1 4 7 (distance of 3 between each consecutive element)
From hand-coding several of these, the number of possible sequences seems to be D ** (L-1)
. At first I only needed 2\**7
, and 128 sequences wasn't that difficult to create by hand. However, I now need 3**7
, and possibly even larger amounts, so I need to write a function.
Python is the language I'm learning. Recursion seems to be the way to do it, but I've only practiced on simple recursion, and I'm stuck as to how precisely to write this. As best as I can work out, I need a function that calls itself from within a for-loop. Does this make sense? Directions to similarly structured functions would be greatly appreciated, as well.
Upvotes: 0
Views: 68
Reputation: 1663
The point of recursion is not only formalizing the code in a recursive way, but orientating your mind in a recursive way. Compare carefully the results for length 3 and length 4 with distance 2.
a. Length 3
1 2 3
1 2 4
1 3 4
1 3 5
b. Length 4
1 2 3 | 4
1 2 3 | 5
1 2 4 | 5
1 2 4 | 6
1 3 4 | 5
1 3 4 | 6
1 3 5 | 6
1 3 5 | 7
In the result of length 4, the right side of | is just the result of length 3. That means the result of N length can be derived from N - 1 length.
Assume that we have already a procedure to solve k - 1 length solve_part(k-1)
, by extending the result of k-1 to next length k next_len(solve_part(k-1) ...)
, this problem is naturally solved in a recursive way.
import itertools
def flatmap(func, *iterable):
return itertools.chain.from_iterable(map(func, *iterable))
def next_distance(eachlist, D):
return map(lambda eachdis: eachlist + [eachlist[-1] + eachdis], range(1,D+1))
def next_len(L,D):
return flatmap(lambda eachlist: next_distance(eachlist, D), L)
def solve_it(leng,dis):
def solve_part(k):
if k == 0:
return [[]]
elif k == 1:
return [[1]]
else:
return next_len(solve_part(k-1),dis)
return solve_part(leng)
result=solve_it(4,2)
print([[i for i in j] for j in result])
Upvotes: 0
Reputation: 11496
You can use itertools.product
and itertools.accumulate
to achieve your desired function:
import itertools
def f(l, d):
for sub in itertools.product(range(1, d+1), repeat=l-1):
yield tuple(itertools.accumulate((1,) + sub))
for l in f(4, 2):
print(l)
(1, 2, 3, 4)
(1, 2, 3, 5)
(1, 2, 4, 5)
(1, 2, 4, 6)
(1, 3, 4, 5)
(1, 3, 4, 6)
(1, 3, 5, 6)
(1, 3, 5, 7)
Upvotes: 2
Reputation: 2220
Here is a quick and dirty implementation
def gen_seq(D, L):
for uple in itertools.product(range(1, D+1), repeat=L-1):
yield tuple(numpy.cumsum((1,) + uple))
Upvotes: 0