2

Introduction:

So I know that there is already a question (Skip multiple iterations in loop) similar to mine with a really good answer, but there are still some open questions for me:


Question 1:

Is there any way of doing it without an iterator?

I am looking for something like * 3:
song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']

for sing in song:
    print(sing, end=" ")
    if sing == 'look':
        continue * 3

expected output:

always look side of life 

Question 2:

If I have to use an iterator object, then is it possible to do it a fixed amount of time?

The original question has a solution like this:

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
song_iter = iter(song)
for sing in song_iter:
    print(sing)
    if sing == 'look':

        next(song_iter)
        next(song_iter)
        next(song_iter)

        print(next(song_iter))

But I want it to do it let's say x = 5 times. It is not possible like this:

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
song_iter = iter(song)
for sing in song_iter:
    print(sing)
    if sing == 'look':

        next(song_iter) * x

        print(next(song_iter))

So how would you do it? I know it is possible to use the function itertools.islice, but is there a way without any libraries?


My Approach:

This works great:

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
song_iter = iter(song)

skip_iterations = 3

for sing in song_iter:
    print(sing)
    if sing == "look":
        while skip_iterations > 0:
            next(song_iter, "")

            skip_iterations -= 1

Output:

always look side of life 

But maybe anyone else has a better idea? :)


Links:

The Question I was mentioning - The Answer for that question

jarmod
  • 71,565
  • 16
  • 115
  • 122
Pixelbog
  • 236
  • 1
  • 8
  • 2
    your approach seems good enough, except I would use a `for` loop: `for _ in range(skip_iterations): next(song_iter)` – Matiiss Dec 19 '21 at 16:49
  • 1
    Every `for` loop uses an iterator, whether you're aware of it or not. Using `iter` simply gives you access to one at the code level. Anyway, it seems like your question is: given an iterator object, how can we call `next` on it a specified number of times? Well - how do you *normally* do *anything* a specified number of times in Python? With... a `for` loop, right? So.... – Karl Knechtel Dec 19 '21 at 16:49
  • "If I have to use an iterator object, then is it possible to do it a fixed amount of time?" - with an arbitrary iterator, no. Iterators are sequential, not random-access. For example, an iterator over a linked list cannot be advanced without following links one by one, and a generator doesn't even have well-defined elements until you run it and make it yield elements one by one. – user2357112 Dec 19 '21 at 16:52
  • If you're just iterating over a list, then you can skip in constant time easily enough, but not with a standard list iterator. You would have to write your own handling. – user2357112 Dec 19 '21 at 16:59

5 Answers5

1

An alternate approach is to have a C style for loop that has more complete update logic:

def cfor(i, test_i, update_i):
    while test_i(i):
        yield i
        i=update_i(i)

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']

skip=3

for i in cfor(0, 
              lambda i: i<len(song), 
              lambda i: i+skip+1 if song[i]=='look' else i+1):
    print(song[i], end=' ')

Or, that can just be a while loop:

idx=0
while(idx<len(song)):
    print(song[idx], end=' ')
    idx+=skip+1 if song[idx]=='look' else 1

If your skip is large, either of these would be faster.


You can also use enumerate with a comprehension:

l=song.index('look')
' '.join([w for i,w in enumerate(song) if i<=l or i>(l+skip)])
dawg
  • 98,345
  • 23
  • 131
  • 206
1

Ans 1 There are many ways to do the problem one of the easiest one would be by checking the index like

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
skip_iterations=3
for i,sing in enumerate(song):
    if not song.index('look') < i < song.index('look')+skip_iterations+1:
    print(sing, end=" ")

'enumerate' returns (index, element) Ans 2 Your method is just fine you may prefer a for loop instead of while loop but thats just a personal suggestion.

Divij Mahajan
  • 76
  • 1
  • 6
0

Question 1

You could employ the use of an iteration bound to keep track of when you can resume evaluation in the loop

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']

iter_bound = -1
for i, sing in enumerate(song):
    if i <= iter_bound:
        continue
    if sing == 'look':
        iter_bound = i + 3
    print(sing, end=" ")

If you use this very often in your code, you may want to code a function around it:

from typing import Iterable, Callable

def skip_n_on_condition(iterator: Iterable, condition: Callable, n_skips: int):
    """Loop over iterable and perform n_skips whenever the condition on the element is met"""
    iter_bound = -1
    for i, element in enumerate(iterator):
        if i <= iter_bound:
            continue
        if condition(element):
            iter_bound = i + 3
        yield element
    
song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']

print(*skip_n_on_condition(song, lambda x: x == 'look', 3), end=" ")

Question 2

Since you know the number of times you will be looping, it may be better to use a for loop. It will also be an implementation that does not change the value of skip_iterations which you may not have expected.

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
song_iter = iter(song)

skip_iterations = 3

for sing in song_iter:
    print(sing)
    if sing == "look":
        for _ in range(skip_iterations):
            next(song_iter, "")

You could make the loop a one liner using a list comprehension.

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
song_iter = iter(song)

skip_iterations = 3

for sing in song_iter:
    print(sing)
    if sing == "look":
        [next(song_iter, "") for _ in range(skip_iterations)]
jongboi
  • 1
  • 1
0

With a skip counter:

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']

skip = 0
for sing in song:
    if skip:
        skip -= 1
        continue
    print(sing, end=" ")
    if sing == 'look':
        skip = 3
Kelly Bundy
  • 23,480
  • 7
  • 29
  • 65
0

I would consider the "historic" way of iterating.

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']

i = 0
while i < len(song):
    sing = song[i]
    i += 1

    print(sing, end=" ")
    if sing == 'look':
        i += 3
        continue

    # ... other code ...
VPfB
  • 14,927
  • 6
  • 41
  • 75