DEV Community

Latz
Latz

Posted on

How to loop through an array with a variable starting element

Recently I was faced with an interesting problem. I needed to create a simplified (pseudo-) cron interface:

Image description

The task is to find the next selected day.

My first attempt was a naive one. Loop to the end of the array and if nothing was found, start a second loop at the beginning and move to the current day (pseudocode, no error detection, performance optimization or edge casing):

$days = Array(false, true, false, true, false, false, false);
$today = 4 // Thursday
$i = today + 1;  // loop index starts at the next day (Friday)
$next = -1;      // loop abort variable
// iterate to the end of the array
while ($i <= $today.length() && $next == -1) {
    if ($days[i] == true) { // day checkbox is selected
      $next = $days[$i];
    }
    $i++;                        
}
// no truthy element was found
if ($next == -1) {
    $i = 0; // start at the beginninf of the array
    // iterate from the start to the current day
    while ($i <= $today && $next == -1) {
        if ($days[i] == true) { // day checkbox is selected
          $next = $i;
        }
        $i++;  
    }
}
print $next; // 1 (Monday)
Enter fullscreen mode Exit fullscreen mode

The problem can be abstracted: Printing all the indices of an array in sequence, using a variable starting point. In the example above: 5, 6, 0, 1, 2, 3, 4.

$start = 4;
$arr = Array(false, true, false, false, true, false, false);
$max = $arr.length;
$i = $start + 1 ;
while ($i < $max) {    
   print ($i);   // 5, 6
   $i++;
}
$i = 0;
while ($i < $start + 1) {
    print ($i);  // 0, 1, 2, 3, 4
    $i++;
}
Enter fullscreen mode Exit fullscreen mode

If you look at the output, you’ll notice that the numbers are all integers and less than or equal to max.
There’s a special, lesser-known operator that comes in handy in this case: modulo. In a nutshell, modulo returns the integer remainder of a division, e.g:

  • 1 mod 5 → 1 (0 remaining 1)
  • 2 mod 5 → 2 (0 remaining 2)
  • 3 mod 5 → 3 (0 remaining 3)
  • 4 mod 5 → 4 (0 remaining 4)
  • 5 mod 5 → 0 (1 remaining 0)
  • 6 mod 5 → 1 (1 remaining 1)
  • 7 mod 5 → 2 (1 remaining 2)

You will notice two things:

  1. the result is always less than or equal to the dividend (5)
  2. the result is repeated after the dividend (1, 2, 3, 4, 5, 6, 7) exceeds the value of the divisor (5).

That’s exactly what we need. Let’s put something like this, with different numbers, into code:

$start = 4;
$max = 7;
$i = $start;
while ($i < $max + $start) {
    print ($i); // 4, 5, 6, 7, 8, 9, 10
    print ($i mod $max); // 4, 5, 6, 0, 1, 2, 3
    $i++;
}
Enter fullscreen mode Exit fullscreen mode

The index i exceeds the length of the array, but we’re using i mod max and not the loop index itself. The result makes a round trip after reaching max and starts again at 0. All indexes of the array are covered, starting from the middle index 4.

The actual code now looks like this:

$days = Array(false, true, false, true, false, false, false);
$today = 4 // THursday

$i = $today + 1;
$max = $days.length;
$next = -1;
while ($i < $max + $today && $next == -1) {
    if ($days[$i mod $max] == true) {
        $next = i mod $max;
    }
    $i++;
}

print ($next); // 1 (Monday)
Enter fullscreen mode Exit fullscreen mode

This code may not look as readable as before, so why are we doing this?

Because we can!

And it’s fun to come up with a clever solution to a problem. We’re programmers, after all.

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay