如何在分区中反转PHP数组

I have a simple array that looks like this:

Array (
    [0] => Array (
        [id] => 8692
        [name] => d
    )
    [1] => Array (
        [id] => 8691
        [name] => c
    )
    [2] => Array (
        [id] => 8690
        [name] => b
    )
    [3] => Array (
        [id] => 8689
        [name] => a
    )
    [4] => Array (
        [id] => 8500
        [name] => d
    )
    [5] => Array (
        [id] => 8499
        [name] => c
    )
    [6] => Array (
        [id] => 8498
        [name] => b
    )
    [7] => Array (
        [id] => 8497
        [name] => a
    )
)

This array is quite long so I only included the first 4 items to give you an idea.

My problem is that I need the array to be in a format of

a,b,c,d,a,b,c,d

At the moment the format is like:

d,c,b,a,d,c,b,a

By this I mean the ['name'] value which is either a,b,c or d.

So I every 4 items in the array need to be reversed.

I have tried to achieve this but fail every time ending up with lots of for & while loops.

You can do it using array_chunk, array_merge and array_reverse:

$finalArray = array();

$arrays = array_chunk($myArray, 4);

foreach ($arrays as $array) {
    $finalArray = array_merge($finalArray, array_reverse($array));
}

You can iterate the array with a for and increment with 4 each time and keep the current offset in other variable and use array_slice to get the current slice of array and reverse order using array_reverse

I am thinking of something like this:

$step = 4;
$offset = 0;
$new_arr = []; //Here we create the new array.
for($i=0; $i<count($arr); $i+=$step) {
   $part_of_array = array_slice($arr, $offset, $step);
   $part_reverse = array_reverse($part_of_array);
   $new_arr = array_merge($new_arr, $part_reverse);
   $offset += $step;
}
print_r($new_arr); //Here will be the array as you expected.

All the content in the for can be simplify to:

   $new_arr = array_merge($new_arr, array_reverse(array_slice($arr, $offset, $step)));
   $offset += $step;

Not harcoding every 4, reverse based on char code of name value

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
/**
*/
$in = [
     ['name'=>'d','id'=>1]
   , ['name'=>'c','id'=>12]
   , ['name'=>'b','id'=>13]
   , ['name'=>'a','id'=>14]
   , ['name'=>'d','id'=>15]
   , ['name'=>'c','id'=>16]
   , ['name'=>'b','id'=>17]
   , ['name'=>'a','id'=>18]
];

$last = PHP_INT_MAX;
$toReverse = [];
$out = [];
foreach ($in as $value) {
    $p = ord($value['name']);
    if ( $p < $last ) {
        //echo 'ToReverse',var_export($value,true),"
";
        $toReverse[] = $value;
    }
    else {
        $out = array_merge($out,array_reverse($toReverse));
        //echo 'Join',var_export($out,true),"
";
        $toReverse = [$value];

    }
    $last = $p;
}
$out = array_merge($out,array_reverse($toReverse));
print_r($out);

All the answers here, while perfectly valid, are pretty much on the order of O(n^2). So I figured I'd give you an O(n / 2), time complexity, solution as an alternative just in case you care about performance. The solution also uses only O(n + n + k) space complexity (in place swap).

Since the requirement is to reverse order of values, I'm ignoring keys and basing the solution on the constraint that the array is always 0-indexed.

To solve this problem, we can generalize the solution as a simple array reverse, which requires a simple O(n/2) operation with in-place swap. We can achieve this simply with two counters, $i starting from the beginning of the array, and $j starting at the end of the array. Thus, we can swap the values at $arr[$i] with that at $arr[$j] and then increment $i and decrement $j, at each step.

function reverseArray(Array $arr) {
    for($i = 0, $j = count($arr); $i < $j; $i++, $j--) {
        $tmp = $arr[$j];
        $arr[$j] = $arr[$i];
        $arr[$i] = $tmp;
    }
    return $arr;
}

Now, to apply the more specific solution of only reverse every group of 4 elements in the array, we just break up the array in partitions of 4 values, and only reverse each of those partitions at a time. Which just expands on the example above of reverseArray() by altering the starting and ending positions of the $i and $j counter to only reverse within each partition.

Thus we arrive the O(n / 2) solution here by just adding another loop for the partition size, and keep the inner loop from the earlier example.

function reverseArrayPartition(Array $arr, $partitionSize = 4) {

    $end = count($arr);

    // reverse only one partition at a time
    for($start = 0; $start < $end; $start += $partitionSize ) {

        $from = $start;
        $to   = $start + $partitionSize - 1;

        for($i = $from, $j = $to; $i < $j; $i++, $j--) {
            // swap the transposing values
            $tmp     = $arr[$j];
            $arr[$j] = $arr[$i];
            $arr[$i] = $tmp;
        }

    }

    return $arr;

}

$arr = [4,3,2,1,4,3,2,1];
var_dump(reverseArrayPartition($arr)); // expected [1,2,3,4,1,2,3,4]

This will work with any array size at any $partitionSize so it's efficient if you're trying to do this on very large arrays.