2
\$\begingroup\$

I am trying to print out numbers by increasing positive and negative values around a center number, and I don't think I've found the best way. For example, say I want to find what number in a list my center value is closest to. I do that by adding one, see if it matches, then subtracting one from the original number and see if that matches, then add two from the original number and so on. I know there are other ways of finding the closest match but I'm not looking for that - I'm looking for the best way to print out numbers steadily getting farther from a center value. Here's my code:

def inc_val(center, i, neg_toggle):
    mult = 1
    if neg_toggle:
        neg_toggle = False
        mult = -1
    else:
        neg_toggle = True
        mult = 1
        i += 1
    val = center + (i * mult)
    return val, i, neg_toggle

i = 0
center = 24
val = center
neg_toggle = False
my_set = {30, 50, 90}
while val not in my_set:
    print(val)
    val, i, neg_toggle = inc_val(center, i, neg_toggle)

This prints out the following list, as desired:

24
25
23
26
22
27
21
28
20
29
19

To be clear, I'm interested in the incrementing numbers. The while not in my_set part is just to illustrate. I am not intentionally trying to re-invent anything, so if there's a built-in or simpler way to do this, please let me know.

\$\endgroup\$
1
\$\begingroup\$

Rather than maintaining the state of the iteration using three variables val, i, and neg_toggle, it would be more elegant to write a generator. Then, the state of the iteration would be maintained by the flow of the execution of the generator itself.

def zoom_out(center):
    decr = center
    incr = center + 1
    while True:
        yield decr
        decr -= 1
        yield incr
        incr += 1

for n in zoom_out(24):
    if n in (30, 50, 90):
        break
    print(n)

Furthermore, fancy iteration can often be expressed more elegantly using itertools. Here, I'd take advantage of itertools.count() to implement the generator, and itertools.takewhile() to detect when to stop executing the infinite generator.

from itertools import count, takewhile

def zoom_out(center):
    decr = count(center, -1)
    incr = count(center + 1)
    while True:
        yield next(decr)
        yield next(incr)

for n in takewhile(lambda n: n not in (30, 50, 90), zoom_out(24)):
    print(n)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.