0

I am working on a program where I need to test each value in a list against a large number of conditions for which I am using a standard for item in list loop. However, in some rare circumstances I need to read in three items to check the condition.

I know that this could be solved by using a while loop and indexing but my code uses a fair few continue blocks and relies heavily on indexing so that seems like an excellent way to introduce hard-to-find bugs.

currently my solution is simply to have a skip_num variable and have the first code within the for loop be:

if skip_num:
    skip_num -= 1
    continue

However, this is still pretty clunky and leaves a variable dangling out there which is able to screw with the reading of the conditions. Can anyone recommend a more elegant way of achieving the same thing? Ideally I would like to do something similar to what the next function does for generator expressions but I know python for loops really hate you trying to mess with their control variable.

Thanks

Clarification: ideally the solution would work something like this:

array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for number in array:
    print(number)
    if number == 5:
        num = number
        next_1 = next(array)
        next_2 = next(array)
        print(f"{num}, {next_1}, {next_2}")


# output
# 1
# 2
# 3
# 4
# 5 6 7 
# 8
# 9
Pioneer_11
  • 670
  • 4
  • 19

3 Answers3

2

I think this is a clean solution:

def gen_tuples(xs):
    ixs = iter(xs)
    for x in ixs:
        if x == 5:
            yield (x, next(ixs), next(ixs))
        else:
            yield (x,)


for t in gen_tuples([1, 2, 3, 4, 5, 6, 7, 8, 9]):
    print(t)

Output:

(1,)
(2,)
(3,)
(4,)
(5, 6, 7)
(8,)
(9,)

The generator always yields a tuple, but of course you could have it yield either a tuple or an int.

Note that it will raise a StopIteration exception if a 5 is encountered too close to the end to be able to return a 3-tuple and it won't do anything special if you have multiple 5's in a row.

If you prefer brevity:

def gen_tuples(xs):
    ixs = iter(xs)
    for x in ixs:
        yield (x, next(ixs), next(ixs)) if x == 5 else (x,)


for t in gen_tuples([1, 2, 3, 4, 5, 6, 7, 8, 9]):
    print(t)
Grismar
  • 27,561
  • 4
  • 31
  • 54
2

By creating an iterator for array using iter(), you can iterate over the elements without introducing an index variable:

array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
it = iter(array)
try:
    number = next(it)
    while True:
        print(number)
        if number == 5:
            num = number
            next_1 = next(it)
            next_2 = next(it)
            print(f"{num}, {next_1}, {next_2}")
        number = next(it)
except (StopIteration):
    pass

Output:

1
2
3
4
5
5, 6, 7
8
9
constantstranger
  • 9,176
  • 2
  • 5
  • 19
0

one thing you can do is converting the list into an iterator object and use the iterator properties such as next() and slice().

for more details I found this answer from a previous post very complete: https://stackoverflow.com/a/22296065/14395688

MPizzotti
  • 81
  • 9