Python iterator with sliced string

Viewed 60

I would like to have infinite iterator/generator with each turn return constant width sliced wrapped-around string. Dead simple code....

s = '123456789 '
it = my_iter(s, 9)
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))

will return:

123456789
23456789 
3456789 1
456789 12

I believe cycle form intercools can be helpful, but I can combine wrapping-around and slicing of cycle. Here is not wrapping version:

def my_iter(s, d):
    i = 0
    while True:
        yield s[i:d+i]
        i = i + 1
2 Answers

The most natural rotation idiom uses deque.rotate:

from collections import deque

def my_iter(s, d):
    q = deque(s)
    while True:
        yield "".join(q)[:d]
        q.rotate(-1)

i = my_iter("123456789 ", 9)
for _ in range(15):
    print(next(i))

123456789
23456789 
3456789 1
456789 12
56789 123
6789 1234
789 12345
89 123456
9 1234567
 12345678
123456789
23456789 
3456789 1
456789 12
56789 123

If you want to restart the iterations once one cycle is over, try:

def my_iter(s, d):
    i = 0
    while True:
        if i > d:
            i = 0
        yield s[i:] + s[:max(0, i - 1)]
        i += 1
        
s = '123456789 '
it = my_iter(s, 9)
for _ in range(20):
    print(next(it))

Output:

123456789 
23456789 
3456789 1
456789 12
56789 123
6789 1234
789 12345
89 123456
9 1234567
 12345678
123456789 
23456789 
3456789 1
456789 12
56789 123
6789 1234
789 12345
89 123456
9 1234567
 12345678

Or if you want to give the same output as the previous runs, try:

def my_iter(s, d):
    i = 0
    while True:
        yield s[i:] + s[:max(0, i - 1)]
        i += 1

s = '123456789 '
it = my_iter(s, 9)
for _ in range(12):
    print(next(it))

Output:

123456789 
23456789 
3456789 1
456789 12
56789 123
6789 1234
789 12345
89 123456
9 1234567
 12345678
123456789
123456789
Related