Home > Mobile >  Cycle loop list with current item and next item
Cycle loop list with current item and next item

Time:10-11

I would like an elegant pythonic way to cycle through a list while having variables that have access to the current item and the next item during the iteration process. This is one method I know of that just gives me the current variable.

from itertools import cycle

stuff = ['a', 'b', 'c', 'd']
print(stuff)
for curr_item in cycle(stuff):
    print("current:", curr_item)

Output:

['a', 'b', 'c', 'd']
current: a
current: b
current: c
current: d
current: a
current: b
current: c
...

Looking for something that kinda looks like:

from itertools import cycle

stuff = ['a', 'b', 'c', 'd']
print(stuff)
for curr_item, next_item in MAGIC(stuff):
    print("current:", curr_item)
    print("next:", next_item)

Desired output:

['a', 'b', 'c', 'd']
current: a
next: b
current: b
next: c
current: c
next: d
current: d
next: a
current: a
next: b
current: b
next: c
current: c
next: d
...

CodePudding user response:

A solution could be leveraging tee() function as follows:

from itertools import cycle, tee

stuff = ['a', 'b', 'c', 'd']
curr_iter, next_iter= tee(cycle(stuff),2)
next(next_iter)

for curr_item, next_item in zip(curr_iter,next_iter):
    print("current:", curr_item)
    print("nex:", next_item)

FYI: shouldn't use next as a variable name since it is already being used as a function name.

CodePudding user response:

we can slightly modify the snippet from this description to make our iterator:

def cycle(itr):
    l = len(itr)
    saved = []
    for i,element in enumerate(itr,1):
        yield element,itr[i%l]
        saved.append(element)
    while saved:
        for j,element in enumerate(saved,1):
              yield element,saved[j%l]


for curr_item, next_item in cycle(stuff):
    print("current:", curr_item)
    print("next:", next_item)

>>> out
'''
current: a
next: b
current: b
next: c
current: c
next: d
current: d
next: a
current: a
next: b
current: b
next: c
current: c
next: d
current: d
next: a
...

or we can make our own (it also shows prev element as a small bonus):

from collections import deque
# supports thread-safe, memory efficient appends and pops from either side of the deque with approximately the same O(1) performance in either direction.

def cycle(iterable):
    itr = deque(iterable)
    while itr:
        yield itr[-1],itr[0],itr[1]
        cur = itr.popleft()
        itr.append(cur)


c = cycle('12345')
for _ in range(10):
    print('previous: {}, current: {}, next: {}'.format(*next(c)))

>>> out
'''
previous: 5, current: 1, next: 2
previous: 1, current: 2, next: 3
previous: 2, current: 3, next: 4
previous: 3, current: 4, next: 5
previous: 4, current: 5, next: 1
previous: 5, current: 1, next: 2
previous: 1, current: 2, next: 3
previous: 2, current: 3, next: 4
previous: 3, current: 4, next: 5
previous: 4, current: 5, next: 1
  • Related