How to iterate through list infinitely with +1 offset each loop
Question:
I want to infinitely iterate through the list from 0 to the end, but in the next loop I want to start at 1 to the end plus 0, and the next loop would start at 2 to the end plus 0, 1, up to the last item where it would start again at 0 and go to the end.
Here is my code:
a = [ 0, 1, 2 ]
offset = 0
rotate = 0
while True:
print(a[rotate])
offset += 1
rotate += 1
if offset >= len(a):
offset = 0
rotate += 1
if rotate >= len(a):
rotate = 0
This is the solution I came up with so far. It’s far from perfect.
The result that I want is:
0, 1, 2 # first iteration
1, 2, 0 # second iteration
2, 0, 1 # third iteration
0, 1, 2 # fourth iteration
and so on.
Answers:
You can create the lists with offsets using list slicing, and then repeat them infinitely using itertools.cycle()
. This computes all of the rotations exactly once, and then cycles through all of them:
from itertools import cycle, islice
lst = [0, 1, 2]
items = [lst[i:] + lst[:i] for i in range(len(lst))]
iterator = cycle(items)
for item in islice(iterator, 10):
print(item)
The above approach is fast once you’ve gotten past the precomputation, but you may (depending on your use case) prefer an approach that does not have an upfront time/space cost. In that case, you can use a generator instead:
from itertools import cycle, islice
def rotate(lst):
for offset in cycle(range(len(lst))):
yield lst[offset:] + lst[:offset]
lst = [0, 1, 2]
for item in islice(rotate(lst), 10):
print(item)
Both of these output:
[0, 1, 2]
[1, 2, 0]
[2, 0, 1]
[0, 1, 2]
[1, 2, 0]
[2, 0, 1]
[0, 1, 2]
[1, 2, 0]
[2, 0, 1]
[0, 1, 2]
These code snippets have been improved from a suggestion by wjandrea.
Try this:
a = [0, 1, 2]
while True:
print(*a, sep=', ')
a.append(a[0])
a.pop(0)
Output:
0, 1, 2
1, 2, 0
2, 0, 1
0, 1, 2
1, 2, 0
2, 0, 1
...
Or, pop
returns the element removed, so it can be simplified
a = [0, 1, 2]
while True:
print(*a, sep=', ')
a.append(a.pop(0))
[Thanks ShadowRanger and Tomerikoo for improvement suggestions.]
Here you have another alternative using pointers:
a = [ 0, 1, 2 ]
i = 0
l = len(a)
while True:
out = []
for j in range(i, i+l):
out.append(a[j%l])
print(out)
i=(i+1)%l
Output:
[0, 1, 2]
[1, 2, 0]
[2, 0, 1]
[0, 1, 2]
[1, 2, 0]
[2, 0, 1]
You can use a deque
which has a built-in and efficient rotate function (~O(1)):
>>> d = deque([0,1,2])
>>> for _ in range(10):
... print(*d)
... d.rotate(-1) # negative -> rotate to the left
...
0 1 2
1 2 0
2 0 1
0 1 2
1 2 0
2 0 1
0 1 2
1 2 0
2 0 1
0 1 2
Another option, using list slicing:
cycles = [a[i:]+a[:i] for i, _ in enumerate(a)]
while True:
for c in cycles: print(c)
Or, if you don’t want to precalculate O(n^2)
space for cycles
, you can keep making the cycles afresh:
from itertools import count
n = len(a)
for i in count():
j = i%n
print(a[j:]+a[:j])
I want to infinitely iterate through the list from 0 to the end, but in the next loop I want to start at 1 to the end plus 0, and the next loop would start at 2 to the end plus 0, 1, up to the last item where it would start again at 0 and go to the end.
Here is my code:
a = [ 0, 1, 2 ]
offset = 0
rotate = 0
while True:
print(a[rotate])
offset += 1
rotate += 1
if offset >= len(a):
offset = 0
rotate += 1
if rotate >= len(a):
rotate = 0
This is the solution I came up with so far. It’s far from perfect.
The result that I want is:
0, 1, 2 # first iteration
1, 2, 0 # second iteration
2, 0, 1 # third iteration
0, 1, 2 # fourth iteration
and so on.
You can create the lists with offsets using list slicing, and then repeat them infinitely using itertools.cycle()
. This computes all of the rotations exactly once, and then cycles through all of them:
from itertools import cycle, islice
lst = [0, 1, 2]
items = [lst[i:] + lst[:i] for i in range(len(lst))]
iterator = cycle(items)
for item in islice(iterator, 10):
print(item)
The above approach is fast once you’ve gotten past the precomputation, but you may (depending on your use case) prefer an approach that does not have an upfront time/space cost. In that case, you can use a generator instead:
from itertools import cycle, islice
def rotate(lst):
for offset in cycle(range(len(lst))):
yield lst[offset:] + lst[:offset]
lst = [0, 1, 2]
for item in islice(rotate(lst), 10):
print(item)
Both of these output:
[0, 1, 2]
[1, 2, 0]
[2, 0, 1]
[0, 1, 2]
[1, 2, 0]
[2, 0, 1]
[0, 1, 2]
[1, 2, 0]
[2, 0, 1]
[0, 1, 2]
These code snippets have been improved from a suggestion by wjandrea.
Try this:
a = [0, 1, 2]
while True:
print(*a, sep=', ')
a.append(a[0])
a.pop(0)
Output:
0, 1, 2
1, 2, 0
2, 0, 1
0, 1, 2
1, 2, 0
2, 0, 1
...
Or, pop
returns the element removed, so it can be simplified
a = [0, 1, 2]
while True:
print(*a, sep=', ')
a.append(a.pop(0))
[Thanks ShadowRanger and Tomerikoo for improvement suggestions.]
Here you have another alternative using pointers:
a = [ 0, 1, 2 ]
i = 0
l = len(a)
while True:
out = []
for j in range(i, i+l):
out.append(a[j%l])
print(out)
i=(i+1)%l
Output:
[0, 1, 2]
[1, 2, 0]
[2, 0, 1]
[0, 1, 2]
[1, 2, 0]
[2, 0, 1]
You can use a deque
which has a built-in and efficient rotate function (~O(1)):
>>> d = deque([0,1,2])
>>> for _ in range(10):
... print(*d)
... d.rotate(-1) # negative -> rotate to the left
...
0 1 2
1 2 0
2 0 1
0 1 2
1 2 0
2 0 1
0 1 2
1 2 0
2 0 1
0 1 2
Another option, using list slicing:
cycles = [a[i:]+a[:i] for i, _ in enumerate(a)]
while True:
for c in cycles: print(c)
Or, if you don’t want to precalculate O(n^2)
space for cycles
, you can keep making the cycles afresh:
from itertools import count
n = len(a)
for i in count():
j = i%n
print(a[j:]+a[:j])