开发者

Rotate array elements to the left (move first element to last and re-index)

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

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

Is th开发者_StackOverflow社区ere some kind of built-in PHP function for this?


  $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
)


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.


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

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


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


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.


you can use this function:

    function arr_rotate(&$array,$rotate_count) {
        for ($i = 0; $i < $rotate_count; $i++) {
            array_push($array, array_shift($array));
        }
    }

usage:

    $xarr = array('1','2','3','4','5');
    arr_rotate($xarr, 2);
    print_r($xarr);

result:

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


There's a task about array rotation on Hackerrank: https://www.hackerrank.com/challenges/array-left-rotation/problem.

And proposed solution with array_push and array_shift will work for all test cases except the last one, which fails due to timeout. So, array_push and array_shift will give you not the fastest solution.

Here's the faster approach:

function leftRotation(array $array, $n) {
   for ($i = 0; $i < $n; $i++) {
       $value = array[$i]; unset(array[$i]); array[] = $value;
   }
   return array;
}


Use array_shift and array_push.


$daynamesArray = array("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday");
array_push($daynamesArray, array_shift($daynamesArray)); //shift by one
array_push($daynamesArray, array_shift($daynamesArray)); //shift by two
print_r($daynamesArray);

The output starts at "Wednesday":

Array ( [0] => Wednesday [1] => Thursday [2] => Friday [3] => Saturday [4] => Sunday [5] => Monday [6] => Tuesday 


Yes it is, here is a function I did myself, where $A is the array and $K the number of times you want to rotate the array:

function solution($A, $K) {

  for($i = 0; $i < $K; $i++): //we cycle $K
    $arrayTemp = $A;
    for($j = 0; $j < count($arrayTemp); $j++): // we cycle the array
       if($j == count($arrayTemp) - 1) $A[0] = $arrayTemp[$j]; // we check for the last position
       else $A[$j + 1] = $arrayTemp[$j]; // all but last position
    endfor;
  endfor;
 return $A;

}


The logic is to swap the elements. Algorithm may look like -

 for i = 0 to arrayLength - 1
    swap( array[i], array[i+1] )     // Now array[i] has array[i+1] value and 
                                     // array[i+1] has array[i] value.


No. Check the documentation for array_shift and its related functions for some tools you can use to write one. There might even be an array_rotate function implemented in the comments of that page.

It's also worth reading through the array functions listed on the left-hand sidebar to get a full understanding of what array functions are available in PHP.


Here's a function to rotate an array (zero-indexed array) to any position you want:

function rotateArray($inputArray, $rotateIndex) {
  if(isset($inputArray[$rotateIndex])) {
    $startSlice = array_slice($inputArray, 0, $rotateIndex);
    $endSlice = array_slice($inputArray, $rotateIndex);
    return array_merge($endSlice, $startSlice);
  }
  return $inputArray;
}

$testArray = [1,2,3,4,5,6];
$testRotates = [3, 5, 0, 101, -5];

foreach($testRotates as $rotateIndex) {
  print_r(rotateArray($testArray, $rotateIndex));
}


Not too dissimilar to the first snippet in ShaunCockerill's answer, I also endorse not making iterated functions calls to perform the rotation. In fact, I'll recommend using early returns to optimize performance and reduce the total number of function calls needed.

The following snippet is the "move left" version of the "move right" version that I posted here. In my demo, there is a single, static input array and the foreach() loop merely changes the desired amount of rotation (0 to 9).

Code: (Demo)

function shiftPop(array $indexedArray, int $shiftPopsCount): array
{
    $count = count($indexedArray);
    if ($count < 2) {
        return $indexedArray;
    }
    $remainder = $shiftPopsCount % $count;
    if (!$remainder) {
        return $indexedArray;
    }
    return array_merge(
        array_splice($indexedArray, $remainder),
        $indexedArray
    );
}

$array = [1, 2, 3, 4];
foreach (range(0, 9) as $moves) {
    var_export(shiftPop($array, $moves));
    echo "\n---\n";
}

The first if block in my snippet is not engaged by my demo because my array always has 4 elements. The second if block is engaged, when $moves is 0, 4, and 8 -- in these cases, the input is identical to the desired output, so calling array_merge() and array_splice() is pointless.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜