2

I am trying to create a function that, for each member of a list, returns the value of that member and the number of values either side of it. The only trick is that it has to "wrap around" when it is at the start or end of the list

For example:

a = [0,1,2,3,4,5,6,7,8,9]  
myfunc(a,2) # 2 indicates 2 either side

[8,9,0,1,2]
[9,0,1,2,3]
[0,1,2,3,4]
...
...
[6,7,8,9,0]
[7,8,9,0,1]

I can work out how to do it from index 2 until 7:

def myfunc(vals, rnge):
    for i in range(0+rnge, len(vals)-rnge):
        print vals[i-rnge:i+rnge+1]

But I can't work out how to handle when it needs to wrap around.

Sam Estep
  • 12,974
  • 2
  • 37
  • 75
guskenny83
  • 1,321
  • 14
  • 27

5 Answers5

2

you could try this (extend vals in both directions first). there may be something in collections that allows for this to be done more efficiently:

def myfunc(vals, rnge):
    vals_ext = vals[-rnge:] + vals + vals[:rnge]
    for i in range(len(vals)):
        print( vals_ext[i:i+2*rnge+1] )

output:

[8, 9, 0, 1, 2]
[9, 0, 1, 2, 3]
[0, 1, 2, 3, 4]
[1, 2, 3, 4, 5]
[2, 3, 4, 5, 6]
[3, 4, 5, 6, 7]
[4, 5, 6, 7, 8]
[5, 6, 7, 8, 9]
[6, 7, 8, 9, 0]
[7, 8, 9, 0, 1]
hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
2

Generate your lists using the numpy element-wise modulo of an (unshifted) array.

You want 5 elements that wrap around 10, so use modulo 10. For example if the list starts with 8:

np.mod(np.arange(8,8+5,1),10)  returns [8, 9, 0, 1, 2]

To get all 10 possible lists, evaluate list(np.mod(np.arange(s,s+5,1),10))for each start s=1,2,..,10

Or, in a single list comprehension without resorting to numpy,

[[t%10 for t in range(s,s+5)] for s in range(10)]

returns

[[0, 1, 2, 3, 4],
 [1, 2, 3, 4, 5],
 [2, 3, 4, 5, 6],
 [3, 4, 5, 6, 7],
 [4, 5, 6, 7, 8],
 [5, 6, 7, 8, 9],
 [6, 7, 8, 9, 0],
 [7, 8, 9, 0, 1],
 [8, 9, 0, 1, 2],
 [9, 0, 1, 2, 3]] 
Mark Greenwood
  • 126
  • 1
  • 5
1

How about:

def myfunc(vals, rnge):
    valsX3 = vals*3;
    for i in range(len(vals)):
        print valsX3[i:i+2*rnge+1]

You could use something like this to avoid the duplication of arrays: wrapping around slices in Python / numpy

Not sure how it does it internally though.

Community
  • 1
  • 1
Nitesh Patel
  • 631
  • 3
  • 10
  • this is similar to the above answer where you extend the list on either side.. is there no way of calculating the indexes? if i have very long arrays of values, or if the lists contain very large and complex objects, then i would imagine doing it this way would be very inefficient.. – guskenny83 Jul 12 '15 at 10:58
  • You could do it as separate operations. Or use this: – Nitesh Patel Jul 12 '15 at 11:02
1

Here is an alternative approach you might also find useful:

def myfunc(alist, offset):
    adeque = collections.deque(a)       
    adeque.rotate(offset)
    for i in xrange(len(alist)):
        print list(itertools.islice(adeque, 0, 2*offset+1))
        adeque.rotate(-1)

a = [0,1,2,3,4,5,6,7,8,9]  
myfunc(a,2) # 2 indicates 2 either side

It makes use of the deque collections object which has an efficient rotate function.

Martin Evans
  • 45,791
  • 17
  • 81
  • 97
-1

Here is the solution :

def defunc(vals, start, rnge):
    n = len(vals)
    new = []

    for i in xrange((start - rnge), (start + rnge)+ 1):
        new.append(vals[i%n])
    return new

def myfunc(vals, rnge):
    n = len(vals)
    for i in range(n):
        print defunc(vals,i,rnge)

I am not slicing the list to make the logic clearer.
I hope this works

Kshitij Saraogi
  • 6,821
  • 8
  • 41
  • 71