Resetting Counter in a While loop

Suppose I want a function to continuously iterate through a set until it is directed to stop. Currently I am using a while loop with an if else statement to reset the counter. So it looks something like.

a=["a","b"]
function test(a)
    cont = Ref(true)
    number = 1
    @async while cont[]
        if number < 3
            println(a[number])
            number+=1
            sleep(5)
        else
            number = 1 
        end
    end
    return(cont)
end

Just wondering if this was the correct approach or if there was a more direct way to do this in Julia?

You could use Iterators.cycle to loop through your array.

cont = Ref(true)
for x in Iterators.cycle(a)
    cont[] || break # if cont[] is false, then break
    f(x) # do something with x
end
2 Likes

awesome thanks! Sorry I’m a little confused about how to break the loop in the REPL. With @async if

j = test(a)

then

j[]=false

breaks the loop but that doesn’t seem to work here.

It seems to work for me.

julia> a = ["a", "b"]
2-element Vector{String}:
 "a"
 "b"

julia> function test2(a)
           cont = Ref(true)
           @async for x in Iterators.cycle(a)
               cont[] || break
               println(x)
               sleep(5)
           end
           return cont
       end
test2 (generic function with 1 method)

julia> c = test2(a);
a

julia> b
a
b
a
julia>

julia> c[]=false
false
# no more output
1 Like

oh gotcha sorry I thought your post meant that you didn’t need the @async with Iterators.cycle. Thanks for clearing that up. Also I could put this in another post if that would be better but was wondering with the Iterators.cycle is it still possible to introduce a pause on every ith iteration? So in a while loop and a counter I could do something like

count = 1 
 while true
    f (a[count:count+n]) # run some function on the first n+1 elements of a
    count+=n
    sleep(5)
end   

could I do something like that with Iterators.cycle or would a counter still be required?

If you want to pause after every i-th iteration, you can wrap the cycle in enumerate.

for (i, x) in enumerate(Iterators.cycle(a))
    cont[] || break
    println(x)
    # Sleep after every fifth iteration
    (i % 5 == 0) && sleep(5)
 end

prints

1 a
2 b
3 c
4 a
5 b
6 c
7 a
[...]

If you want to pause after processing every i-th element of your input array a, then you can just swap enumerate and Iterators.cycle (i.e., Iterators.cycle(enumerate(a))) which will produce pairs (i, a[i]) forever.

I also see that you sketched something that looks like batch processing (a[count:count+n]). If that’s your intention, you can use Iterators.partition for that.

For example:

julia> a = ["a", "b", "c", "d", "e", "f", "g"];

julia> function test(a)
           cont = Ref(true)
           # Use batches of maximum size 3
           batches = Iterators.partition(A, 3)

           @async for (i, x) in enumerate(Iterators.cycle(batches))
               cont[] || break
               println(i, ' ', x)

               if i % 2 == 0
                   println("Sleeping...")
                   sleep(2)
               end
           end
           return cont
       end
test (generic function with 1 method)

julia> c = test(a);

prints

1 ["a", "b", "c"]
2 ["d", "e", "f"]
Sleeping...
3 ["g"]
4 ["a", "b", "c"]
Sleeping...
5 ["d", "e", "f"]
6 ["g"]
Sleeping...
7 ["a", "b", "c"]
8 ["d", "e", "f"]
Sleeping...
9 ["g"]
10 ["a", "b", "c"]
Sleeping...
11 ["d", "e", "f"]
12 ["g"]
Sleeping...
13 ["a", "b", "c"]
14 ["d", "e", "f"]
Sleeping...
[...]

It processes the array in batches of size 3, and after processing every second batch, it sleeps.

2 Likes

Sorry just saw this but… wow thank you this is so incredibly helpful!!