向左旋转数组元素(将第一个元素移动到最后一个元素并重新编制索引)


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

是否可以在PHP中轻松"旋转"数组?

喜欢这个:1

, 2, 3, 4 -> 2, 3 ,4 ,1

有没有某种内置的PHP函数?

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

输出

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

大多数当前的答案都是正确的,但前提是您不关心索引:

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

输出:

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

要保留索引,您可以执行以下操作:

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

输出:

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

也许有人可以比我的四线方法更简洁地进行旋转,但这无论如何都有效。

这非常简单,可以通过多种方式完成。例:

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

遍历数组并shift -ing 和 push -ing 可能是轮换数组的常用方法,但它通常会弄乱您的键。更可靠的方法是结合使用array_mergearray_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);

或者,如果您还发现需要轮换键以使它们与不同的值匹配,则可以组合 array_keysarray_combinearray_rotatearray_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
    );
}

或者轮换值,同时保持键的顺序相同(相当于在匹配的函数调用中调用负距离array_rotate_key(。

/**
 * 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
    );
}

最后,如果您想防止数字索引的重新编号。

/**
 * 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
    );
}

执行一些基准测试可能是有益的,但是,我希望无论使用哪种方法,每个请求的少量轮换都不会显着影响性能。

也应该可以使用自定义排序函数旋转数组,但它很可能过于复杂。 usort .

一种维护密钥和轮换的方法。 使用与 array_push(数组,array_shift(array((相同的概念,我们将使用 2 个array_merge array_slices

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

将第一个元素移动到末尾

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

将最后一个元素移到前面

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

您可以使用此函数:

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

用法:

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

结果:

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

在 Hackerrank 上有一个关于数组旋转的任务:https://www.hackerrank.com/challenges/array-left-rotation/problem。

并且建议的具有array_pusharray_shift的解决方案将适用于所有测试用例,但最后一个测试用例除外,最后一个测试用例因超时而失败。因此,array_pusharray_shift不会为您提供最快的解决方案。

这是更快的方法:

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

使用 array_shiftarray_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);

输出从"星期三"开始:

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

是的,这是我自己做的一个函数,其中$A是数组,$K要旋转数组的次数:

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;
}

逻辑是交换元素。算法可能看起来像 -

 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. 查看文档以了解array_shift及其相关函数,了解可用于编写文档的一些工具。 在该页面的评论中甚至可能实现array_rotate函数。

还值得通读左侧边栏上列出的数组函数,以全面了解 PHP 中可用的数组函数。

下面是一个将数组(零索引数组(旋转到您想要的任何位置的函数:

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));
}

这是核心解决方案:(即使 shiftBy 大于数组长度,也要移位(

function rotate($array, $shiftBy)
{
    $res = [];
    $c   = count($array);
    for ($i = 0; $i < $c; $i++) {
        $n       = ($i + $shiftBy) % $c; // mod will take care of positions if rotates
        $res[$n] = $array[$i];
    }
    ksort($res);
    return $res;
}

烧掉这个,你会得到它。

与 ShaunCockerill 答案中的第一个片段不太相似,我也赞成不进行迭代函数调用来执行旋转。 事实上,我建议使用早期return来优化性能并减少所需的函数调用总数。

以下片段是我在此处发布的"向右移动"版本的"向左移动"版本。 在我的演示中,有一个静态输入数组,foreach()循环只是改变所需的旋转量(0 到 9(。

代码:(演示(

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";
}

我的代码段中的第一个if块没有被我的演示使用,因为我的数组总是有 4 个元素。 当$moves 048时,第二个if块被接合——在这些情况下,输入与期望的输出相同,因此调用array_merge()array_splice()是没有意义的。