Given a range, how could I find all sets of size x that meet the specific criteria of being at least x distance apart, not exceeding the range maximum?
If I wanted to find sets of three numbers that are 5 apart in a range of 30, I'd expect to get these values back:
[0,5,10]
[0,6,11]
[0,7,12]
..etc
[1,6,11]
[1,7,12]
[1,8,13]
..etc
I've looked at itertools, thinking there would be a quick solve there - but I'm not seeing a clear method.
I've tried to harvest all valid runs of numbers doing something like:
lst = [(x,x+5,x+10) for x in range(20)]
But that only get's me +5 values, not values that are +6, +7, etc. Remember, my distance requirement is a minimum.
Any guidance would be appreciated.
I'm new to Python and to Stackoverflow, so if my question is malformed or unclear or ridiculous, please go easy on me - I'm ready to clarify or continue researching as needed; I'm just stuck at the moment. This seems like something that exists and I just can't find vs. something I need to try to cook up with nested iterations.
Thanks again!
>>> print [[x,y,z] for x in range(20) for y in range(x+5,20) for z in range(y+5,20)]
[[0, 5, 10], [0, 5, 11], [0, 5, 12], [0, 5, 13], ..., [8, 13, 19], [8, 14, 19], [9, 14, 19]]
>>>
Addendum
The OP asked for a general solution, the simplest form of a general solution is by code generation and this is my attempt at that
In [3]: def apart(top, delta, n):
vars = ['x%d'%x for x in range(n)]
code = '[['+','.join(vars)+'] for '+vars[0]+ ' in range(%d) '%top
code = code + ' '.join(['for %s in range(%s+%d,%d)'%(xt,xl,d,t) for d,t in [(delta,top)] for xl,xt in zip(vars[:-1],vars[1:])])+']'
return code
...:
In [4]: apart(30,5,4)
Out[4]: '[[x0,x1,x2,x3] for x0 in range(30) for x1 in range(x0+5,30) for x2 in range(x1+5,30) for x3 in range(x2+5,30)]'
In [5]: apart(25,7,2)
Out[5]: '[[x0,x1] for x0 in range(25) for x1 in range(x0+7,25)]'
In [6]:
[(x,y,z) for x in range(20) for y in range(20) for z in range(20) if y>=x+5 and z>=y+5]
Had earlier posted it as comment
You could throw recursion at the problem (this could be prettied up a bit):
def jump(n, min_gap, right_bound, so_far=None):
if so_far is None: so_far = []
if n == 0:
yield so_far
else:
min_x0 = 0 if not so_far else so_far[-1] + min_gap
for i in range(min_x0, right_bound):
for child in jump(n-1, min_gap, right_bound, so_far+[i]):
yield child
which gives
>>> pprint.pprint(list(jump(3, 1, 5)))
[[0, 1, 2],
[0, 1, 3],
[0, 1, 4],
[0, 2, 3],
[0, 2, 4],
[0, 3, 4],
[1, 2, 3],
[1, 2, 4],
[1, 3, 4],
[2, 3, 4]]
>>> pprint.pprint(list(jump(3, 2, 5)))
[[0, 2, 4]]
and matches @gboffi's results:
>>> list(jump(3, 5, 20)) == [[x,y,z] for x in range(20) for y in range(x+5,20) for z in range(y+5,20)]
True
>>> list(jump(4,5,30)) == eval(apart(30,5,4))
True
Try this
r=[]
for a in range(20):
for b in range(20):
for c in range(20):
if b>=a+5 and c>=a+10 and c>=b+5:
r.append((a,b,c))
print(r)
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