Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create circular iterator from incremental start position

OK so I want to create within a loop iterator in index that goes like this

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

where the maximum value may be 8 or another number.

so far I have some code that doesn't work.

a = ['l','m','n','o','p','q','r','s','t'] #len(a) = 9
b = [[]] *len(a)
c = [[]] *len(a)
for offset_index in range(len(a)):
    b[offset_index] = []
    c[offset_index] = []
    for i in range(offset_index, len(a) - offset_index, 1):
        b[offset_index].append(i)
        c[offset_index].append(a[i])
print b

[[0, 1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [3, 4, 5], [4], [], [], [], []]

I can see it's a problem with the 2nd range function, but can't imagine a neat fix.

like image 680
Joylove Avatar asked Mar 07 '23 20:03

Joylove


1 Answers

itertools.cycle + itertools.islice

Efficient cycling and iteration — no copies were harmed in the process of writing this solution.

from itertools import cycle, islice

l = list(range(9))
repeats = 8

[list(islice(cycle(l), i, len(l) + i)) for i in range(repeats)]

[[0, 1, 2, 3, 4, 5, 6, 7, 8],
 [1, 2, 3, 4, 5, 6, 7, 8, 0],
 [2, 3, 4, 5, 6, 7, 8, 0, 1],
 [3, 4, 5, 6, 7, 8, 0, 1, 2],
 [4, 5, 6, 7, 8, 0, 1, 2, 3],
 [5, 6, 7, 8, 0, 1, 2, 3, 4],
 [6, 7, 8, 0, 1, 2, 3, 4, 5],
 [7, 8, 0, 1, 2, 3, 4, 5, 6]]

Or, if you don't want to preserve the indices:

for i in range(repeats):
    idx = list(islice(cycle(l), i, len(l) + i)) 
    ... # do something with idx

List Comprehension

The choice of users looking for performance.

[l[i:] + l[:i] for i in range(repeats)]

[[0, 1, 2, 3, 4, 5, 6, 7, 8],
 [1, 2, 3, 4, 5, 6, 7, 8, 0],
 [2, 3, 4, 5, 6, 7, 8, 0, 1],
 [3, 4, 5, 6, 7, 8, 0, 1, 2],
 [4, 5, 6, 7, 8, 0, 1, 2, 3],
 [5, 6, 7, 8, 0, 1, 2, 3, 4],
 [6, 7, 8, 0, 1, 2, 3, 4, 5],
 [7, 8, 0, 1, 2, 3, 4, 5, 6]]
like image 93
cs95 Avatar answered Mar 20 '23 14:03

cs95