Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: find all sets of numbers inside a range where each set contains values that are x distance apart and don't exceed the range

Tags:

python

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!

like image 734
user3369105 Avatar asked Jan 29 '15 15:01

user3369105


4 Answers

>>> 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]: 
like image 83
gboffi Avatar answered Oct 21 '22 21:10

gboffi


[(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

like image 32
Bhargav Rao Avatar answered Oct 21 '22 23:10

Bhargav Rao


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
like image 24
DSM Avatar answered Oct 21 '22 21:10

DSM


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)
like image 41
Sailesh Kotha Avatar answered Oct 21 '22 23:10

Sailesh Kotha