Cesar Bielich
Cesar Bielich

Reputation: 4945

How to start looping through an array at a different index and finishing the entire array

I am trying to figure out how I can start looping through an array at a different index but when it reaches the end it loops back to the beginning and finishes the array. Basically, I need to be able to dynamically change the offset of the array.

What I am trying to do it associate a letter of the alphabet with a different alphabet letter to mix things up for a string.

Let's say I have a random array like so

$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');

Then I have a string like so

$string = 'abcde';

And let's say I need to start at index in the array at 2 which would be 'c' => 'j' then finish the array to the end and then loop back to the beginning until it is finished.

What I want to do is replace each letter with the corresponding letter associated with it in the array. So the final string after it is replaced would look like

I would reconstruct the array with

$build = strtr($string,$arr);

which would echo gwjyk

But I need to start at a random point in the array and then finish it and go back to the beggining and finish the entire array.

So maybe I have an offset of 2.

$offset = 2;

Upvotes: 1

Views: 723

Answers (5)

random_user_name
random_user_name

Reputation: 26160

As I mentioned in the comments, I would approach this using array_slice and then merging the two arrays in order to simply get a new array, then loop through it from start to finish.

Here's a fully functional solution (and a runnable version)- although I'd like to point out that the offset really doesn't change the results at all:

/**
 * Goes through a string and replaces letters based on an array "map".
 * 
 * @param string - $string
 * @param int - $offset
 * 
 * @return string
 */
function change_letters( $string, $offset ) {
    $letters = ['a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k'];
    // some defensive code to prevent notices or errors
    if ( (int)$offset > count($letters)) {
        echo '<p>Error: Offset is larger than the array of letters!</p>';
        return $string;
    }
    // build new array based on passed-in offset
    $new_array = array_slice($letters, $offset) + array_slice($letters, 0, $offset);
    // at this point, array is ['c' => 'j', 'd' => 'y', 'e' => 'k', 'a' => 'g', 'b' => 'w']
    // loop through the letters to replace...
    foreach($new_array AS $from => $to) {
        // swaps all instances of the "from" letter to the "to" letter in the string.
        // NOTE: this could be easily modified to only replace n instances of the "from" letter
        // like so: $string = str_ireplace( $from, $to, $string, 1); - would only replace 1 instance
        $string = str_ireplace( $from, $to, $string );
    }

    return $string;
}

// Sample usage:
$word = 'abcde';
$new_word = change_letters( $word, 2); // "gwjk"
var_dump(2, $new_word);
$new_word = change_letters( $word, 5); // "gwjk"
var_dump(5, $new_word);
$new_word = change_letters( $word, 6); // "abcde"
var_dump(5, $new_word);

Upvotes: 1

misorude
misorude

Reputation: 3431

All that array slicin’n’dicing or using two loops to loop from x to end first, and start up to x second, is fine … but they don’t make for the most readable code IMHO.

Such an “offsetted circling-through” can be achieved in a quite trivial way with a numerically indexed array - a simple for loop, and the index “clamped down” by using modulo with the total number of array elements.

So in a case like this, I would perhaps prefer the following approach:

$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');

$c = count($arr);
$search = array_keys($arr);
$replace = array_values($arr);

$offset = 2; // zero-based

for( $i = 0; $i < $c; ++$i ) {
  $idx = ( $i + $offset ) % $c;
  echo $search[$idx] . ' =&gt; ' . $replace[$idx] . "<br>\n";
}

// result:
// c => j
// d => y
// e => k
// a => g
// b => w

Upvotes: 0

The fourth bird
The fourth bird

Reputation: 163362

As mentioned in the comment, another option for your example data could be using array_slice and setting the offset and the length parameters and use array_merge:

$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');

$top = array_slice($arr, 0, 2);
$rest = array_slice($arr, 2);

print_r(array_merge($rest, $top));

Array
(
    [c] => j
    [d] => y
    [e] => k
    [a] => g
    [b] => w
)

Upvotes: 0

dazed-and-confused
dazed-and-confused

Reputation: 1333

This will test all possible offsets for the string

$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');
$str = "abcde";
$strlen = strlen($str);
$keys = array_keys($arr);

for ($j = 0; $j < $strlen; $j++) 
{
    $startIndex = $j;
    echo "offset: " . $startIndex . ": ";

    for ($i = $startIndex; $i < $strlen; $i++ ) 
    {
        $char = substr( $str, $i, 1 );
        echo $arr[$char];
    }
    for ($i = 0; $i < $startIndex; $i++ ) 
    {
        $char = substr( $str, $i, 1 );
        echo $arr[$char];
    }
    echo "\n";
}

Output:

offset: 0: gwjyk
offset: 1: wjykg
offset: 2: jykgw
offset: 3: ykgwj
offset: 4: kgwjy

Upvotes: 0

You can try:

<?php

$arr = array(1 => 2, 3 => 4, 5 => 6, 7 => 8, 9 => 0);
$STARTING_KEY = 3;

$array_keys = array_keys($arr);
$starting_index = array_search($STARTING_KEY, $array_keys);

for ($i = $starting_index; $i < sizeof($arr); $i++) {
    echo $arr[$array_keys[$i]] . "\n";
}
for ($i = 0; $i < $starting_index; $i++) {
    echo $arr[$array_keys[$i]] . "\n";
}

Upvotes: 0

Related Questions