PHP: 'rotate' an array?

24,635

Solution 1

Most of the current answers are correct, but only if you don't care about your indices:

$arr = array('foo' => 'bar', 'baz' => 'qux', 'wibble' => 'wobble');
array_push($arr, array_shift($arr));
print_r($arr);

Output:

Array
(
    [baz] => qux
    [wibble] => wobble
    [0] => bar
)

To preserve your indices you can do something like:

$arr = array('foo' => 'bar', 'baz' => 'qux', 'wibble' => 'wobble');

$keys = array_keys($arr);
$val = $arr[$keys[0]];
unset($arr[$keys[0]]);
$arr[$keys[0]] = $val;

print_r($arr);

Output:

Array
(
    [baz] => qux
    [wibble] => wobble
    [foo] => bar
)

Perhaps someone can do the rotation more succinctly than my four-line method, but this works anyway.

Solution 2

  $numbers = array(1,2,3,4);
  array_push($numbers, array_shift($numbers));
  print_r($numbers);

Output

Array
(
    [0] => 2
    [1] => 3
    [2] => 4
    [3] => 1
)

Solution 3

It's very simple and could be done in many ways. Example:

$array   = array( 'a', 'b', 'c' );
$array[] = array_shift( $array );

Solution 4

A method to maintain keys and rotate. using the same concept as array_push(array, array_shift(array)), instead we will use array_merge of 2 array_slices

$x = array("a" => 1, "b" => 2, "c" => 3, 'd' => 4);

To move the First element to the end

array_merge(array_slice($x, 1, NULL, true), array_slice($x, 0, 1, true) //'b'=>2, 'c'=>3, 'd'=>4, 'a'=>1

To move the last element to the front

array_merge(array_slice($x, count($x) -1, 1, true), array_slice($x, 0, //'d'=>4, 'a'=>1, 'b'=>2, 'c'=>3

Solution 5

Looping through the array, and shift-ing and push-ing, may be a common way to rotate an array, however it can often mess up your keys. A more robust method is using a combination of array_merge and array_splice.

/**
 * Rotates an array.
 * 
 * Numerical indexes will be renumbered automatically.
 * Associations will be kept for keys which are strings.
 * 
 * Rotations will always occur similar to shift and push,
 * where the number of items denoted by the distance are
 * removed from the start of the array and are appended.
 * 
 * Negative distances work in reverse, and are similar to
 * pop and unshift instead.
 * 
 * Distance magnitudes greater than the length of the array
 * can be interpreted as rotating an array more than a full
 * rotation. This will be reduced to calculate the remaining
 * rotation after all full rotations.
 * 
 * @param array $array The original array to rotate.
 * Passing a reference may cause the original array to be truncated.
 * @param int $distance The number of elements to move to the end.
 * Distance is automatically interpreted as an integer.
 * @return array The modified array.
 */
function array_rotate($array, $distance = 1) {
    settype($array, 'array');
    $distance %= count($array);
    return array_merge(
        array_splice($array, $distance), // Last elements  - moved to the start
        $array                          //  First elements - appended to the end
    );
}
// Example rotating an array 180°.
$rotated_180 = array_rotate($array, count($array) / 2);

Alternatively, if you also find the need to rotate keys so that they match with different values, you can combine array_keys, array_combine, array_rotate, and array_values.

/**
 * Rotates the keys of an array while keeping values in the same order.
 * 
 * @see array_rotate(); for function arguments and output.
 */
function array_rotate_key($array, $distance = 1) {
    $keys = array_keys((array)$array);
    return array_combine(
        array_rotate($keys, $distance), // Rotated keys
        array_values((array)$array)    //  Values
    );
}

Or alternatively rotating the values while keeping the keys in the same order (equivalent to calling the negative distance on the matching array_rotate_key function call).

/**
 * Rotates the values of an array while keeping keys in the same order.
 * 
 * @see array_rotate(); for function arguments and output.
 */
function array_rotate_value($array, $distance = 1) {
    $values = array_values((array)$array);
    return array_combine(
        array_keys((array)$array),        // Keys
        array_rotate($values, $distance) //  Rotated values
    );
}

And finally, if you want to prevent renumbering of numerical indexes.

/**
 * Rotates an array while keeping all key and value association.
 * 
 * @see array_rotate(); for function arguments and output.
 */
function array_rotate_assoc($array, $distance = 1) {
    $keys = array_keys((array)$array);
    $values = array_values((array)$array);
    return array_combine(
        array_rotate($keys, $distance),   // Rotated keys
        array_rotate($values, $distance) //  Rotated values
    );
}

It could be beneficial to perform some benchmark tests, however, I expect that a small handful of rotations per request wouldn't affect performance noticeably regardless of which method is used.

It should also be possible to rotate an array by using a custom sorting function, but it would most likely be overly complicated. i.e. usort.

Share:
24,635
Dylan
Author by

Dylan

Updated on June 25, 2020

Comments

  • Dylan
    Dylan almost 4 years

    is it possible to easily 'rotate' an array in PHP ?

    Like this: 1, 2, 3, 4 -> 2, 3 ,4 ,1

    Is there some kind of built-in PHP function for this?