PHP平面数组嵌套['a','b','c']到['a'=> ['b'=>'c']] - 高级[关闭]

I need an improved version of this task:

PHP flat array to nested ["a", "b", "c"] to ["a" =>["b"=>["c"]]]

I want to convert:

[
    ['2015', '01', 'Sydney', 12],
    ['2015', '01', 'London', 34],
    ['2015', '02', 'Sydney', 56],
]

to the following: eg if level == 2:

$data[2015]['01'] = ['London', 34]; 
// note 2015, 01, Syney, 12 is overwritten by later record as they have same array keys
$data[2015]['02'] = ['Sydney', 56];

if level === 3:

$data[2015]['01']['Sydney'] = 12; 
//only one element auto convert to value instead of array
$data[2015]['01']['London'] = 34;
$data[2015]['02']['Sydney'] = 56;

And here is a working version: which need improve

<?php
$rows = array(
    array('year' => 2015, 'month' => '01', 'city' => 'Sydney', 'qty' => 12),
    array('year' => 2015, 'month' => '01', 'city' => 'London', 'qty' => 34),
    array('year' => 2015, 'month' => '02', 'city' => 'Sydney', 'qty' => 56),
);
echo '<pre>';
echo 'original data =';
print_r($rows);

echo "
 level=2 and result =
";
$data = arr($rows);
print_r($data);

echo "
 level=3 and result =
";
$data = arr($rows, 3);
print_r($data);

function arr($rows = array(), $level = 2) {
    foreach ($rows[0] as $k => $v) $col[] = $k;
    $num = count($col);
    if ($num < 1) return;//err no data
    if ($num ==1) return; //donot worry this i will figure out later
    if ($level > $num) $level = $num;
    $arr = array();
    foreach ($rows as $row) {
        $k=$col[0]; $ref=&$arr[$row[$k]]; unset($row[$k]);
        if ($level>1){
            $k=$col[1]; $ref=&$ref[$row[$k]]; unset($row[$k]);
            if ($level>2){
                $k=$col[2]; $ref=&$ref[$row[$k]]; unset($row[$k]);
                if ($level>3){
                    $k=$col[3]; $ref=&$ref[$row[$k]]; unset($row[$k]);
                    if ($level>4){
                        $k=$col[4]; $ref=&$ref[$row[$k]]; unset($row[$k]);
                        if ($level>5){//too geek! max 6 level
                            $k=$col[5]; $ref=&$ref[$row[$k]]; unset($row[$k]);
                            $ref=(count($row)<2 ? current($row) : $row);
                        }else $ref=(count($row)<2 ? current($row) : $row);
                    }else $ref=(count($row)<2 ? current($row) : $row);
                }else $ref=(count($row)<2 ? current($row) : $row);
            }else $ref=(count($row)<2 ? current($row) : $row);
        }else $ref=(count($row)<2 ? current($row) : $row);
    }
    return $arr;
}

And I have a new solution:

<?php
$arr = [
    ['y'=>2014, 'm'=>10, 'd'=>10, 'q'=>20141010, 't'=>1],
    ['y'=>2014, 'm'=>10, 'd'=>15, 'q'=>20141015, 't'=>2],
    ['y'=>2014, 'm'=>12, 'd'=>11, 'q'=>20141211, 't'=>3],
    ['y'=>2014, 'm'=>12, 'd'=>22, 'q'=>20141222, 't'=>4],
    ['y'=>2015, 'm'=>10, 'd'=>12, 'q'=>20151012, 't'=>5],
    ['y'=>2015, 'm'=>12, 'd'=>25, 'q'=>20151225, 't'=>6],
];
echo '<pre>origin=';
print_r($arr);
echo 'level=0';
print_r(arr($arr));
echo 'level=1';
print_r(arr($arr, 1));
echo 'level=2';
print_r(arr($arr, 2));
echo 'level=3';
print_r(arr($arr, 3));
echo 'level=4';
print_r(arr($arr, 4));
echo 'level=5';
print_r(arr($arr, 5));

function arr($arr = [], $level = 0) {
    $num = count($arr[0]);
    if (!$num) return []; //no data
    if ($level >= $num) $level = $num - 1;

    if ($level < 1) {
        if ($num === 1) {
            foreach ($arr as $r) {
                $data[] = reset($r);
            }
            return $data;
        }
        return $arr;
    }

    $keys = array_keys($arr[0]);
    $keys = array_slice($keys, 0, $level);
    echo "
keys=";
    print_r($keys);
    foreach ($arr as $i => $r) {
        $ref = &$data[$r[$keys[0]]];
        foreach ($keys as $j => $k) {
            if ($j) {
                $key = $r[$k];
                $ref = &$ref[$key];
            }
            unset($r[$k]);
        }
        $ref = count($r) > 1 ? $r : reset($r);
    }
    return $data;
}

and here is the new result:

origin=Array
(
[0] => Array
    (
        [y] => 2014
        [m] => 10
        [d] => 10
        [q] => 20141010
        [t] => 1
    )

[1] => Array
    (
        [y] => 2014
        [m] => 10
        [d] => 15
        [q] => 20141015
        [t] => 2
    )

[2] => Array
    (
        [y] => 2014
        [m] => 12
        [d] => 11
        [q] => 20141211
        [t] => 3
    )

[3] => Array
    (
        [y] => 2014
        [m] => 12
        [d] => 22
        [q] => 20141222
        [t] => 4
    )

[4] => Array
    (
        [y] => 2015
        [m] => 10
        [d] => 12
        [q] => 20151012
        [t] => 5
    )

[5] => Array
    (
        [y] => 2015
        [m] => 12
        [d] => 25
        [q] => 20151225
        [t] => 6
    )

)
level=0Array
(
[0] => Array
    (
        [y] => 2014
        [m] => 10
        [d] => 10
        [q] => 20141010
        [t] => 1
    )

[1] => Array
    (
        [y] => 2014
        [m] => 10
        [d] => 15
        [q] => 20141015
        [t] => 2
    )

[2] => Array
    (
        [y] => 2014
        [m] => 12
        [d] => 11
        [q] => 20141211
        [t] => 3
    )

[3] => Array
    (
        [y] => 2014
        [m] => 12
        [d] => 22
        [q] => 20141222
        [t] => 4
    )

[4] => Array
    (
        [y] => 2015
        [m] => 10
        [d] => 12
        [q] => 20151012
        [t] => 5
    )

[5] => Array
    (
        [y] => 2015
        [m] => 12
        [d] => 25
        [q] => 20151225
        [t] => 6
    )

)
level=1
keys=Array
(
[0] => y
)
Array
(
[2014] => Array
    (
        [m] => 12
        [d] => 22
        [q] => 20141222
        [t] => 4
    )

[2015] => Array
    (
        [m] => 12
        [d] => 25
        [q] => 20151225
        [t] => 6
    )

)
level=2
keys=Array
(
[0] => y
[1] => m
)
Array
(
[2014] => Array
    (
        [10] => Array
            (
                [d] => 15
                [q] => 20141015
                [t] => 2
            )

        [12] => Array
            (
                [d] => 22
                [q] => 20141222
                [t] => 4
            )

    )

[2015] => Array
    (
        [10] => Array
            (
                [d] => 12
                [q] => 20151012
                [t] => 5
            )

        [12] => Array
            (
                [d] => 25
                [q] => 20151225
                [t] => 6
            )

    )

)
level=3
keys=Array
(
[0] => y
[1] => m
[2] => d
)
Array
(
[2014] => Array
    (
        [10] => Array
            (
                [10] => Array
                    (
                        [q] => 20141010
                        [t] => 1
                    )

                [15] => Array
                    (
                        [q] => 20141015
                        [t] => 2
                    )

            )

        [12] => Array
            (
                [11] => Array
                    (
                        [q] => 20141211
                        [t] => 3
                    )

                [22] => Array
                    (
                        [q] => 20141222
                        [t] => 4
                    )

            )

    )

[2015] => Array
    (
        [10] => Array
            (
                [12] => Array
                    (
                        [q] => 20151012
                        [t] => 5
                    )

            )

        [12] => Array
            (
                [25] => Array
                    (
                        [q] => 20151225
                        [t] => 6
                    )

            )

    )

)
level=4
keys=Array
(
[0] => y
[1] => m
[2] => d
[3] => q
)
Array
(
[2014] => Array
    (
        [10] => Array
            (
                [10] => Array
                    (
                        [20141010] => 1
                    )

                [15] => Array
                    (
                        [20141015] => 2
                    )

            )

        [12] => Array
            (
                [11] => Array
                    (
                        [20141211] => 3
                    )

                [22] => Array
                    (
                        [20141222] => 4
                    )

            )

    )

[2015] => Array
    (
        [10] => Array
            (
                [12] => Array
                    (
                        [20151012] => 5
                    )

            )

        [12] => Array
            (
                [25] => Array
                    (
                        [20151225] => 6
                    )

            )

    )

)
level=5 same as level=4 

(1) Updated to support multiple arrays at once

(2) Updated to merge all child arrays into one array

You can do this by using deneds answer and specifying a level that gets decremented on every recursion. I'm using deneds solution as an anonymous recursive function inside a foreach loop:

function nested(array $array, $level = 1)
{
    for ($i = 0; $i < count($array); ++$i) {
        $nest = function(array $a, $l = 1) use (&$nest) {
            return count($a) < 2
                ? $a[0]
                : ($l == 0 ? $a : [array_shift($a) => $nest($a, --$l)]);
        };

        $array[$i] = count($array[$i]) == 0 ? [] : $nest(array_values($array[$i]), $level);
    }

    return array_replace_recursive(...$array); // Splat-Operator available in PHP >= 5.6
    // array_merge_recursive() does not work on numerical keys
}

$data = array(
    array('year' => 2015, 'month' => '01', 'city' => 'Sydney', 'qty' => 12),
    array('year' => 2015, 'month' => '01', 'city' => 'London', 'qty' => 34),
    array('year' => 2015, 'month' => '02', 'city' => 'Sydney', 'qty' => 56),
);

var_dump( nested($data, 2) );

This will output:

enter image description here

If there's only one array left, the value of the only array element will be applied:

var_dump( nested($data, 3) );

Will result in:

enter image description here

you can tweek Dened's answer by doing something like this:

<?php
function nested(array $array, $level) {
    return count($array) < 2 || $level == 0 ? $array : [array_shift($array) => nested($array, --$level)];
}

function arr_loop($data, $level = 1){
    foreach($data as &$row){
        $row = nested($row, $level);
    }
    return $data;
}

$data = array(
    array('year' => 2015, 'month' => '01', 'city' => 'Sydney', 'qty' => 12),
    array('year' => 2015, 'month' => '01', 'city' => 'London', 'qty' => 34),
    array('year' => 2015, 'month' => '02', 'city' => 'Sydney', 'qty' => 56),
);

echo '<pre>';
var_dump(arr_loop($data,2));
echo '</pre>';
?>

output:

array(3) {
  [0]=>
  array(1) {
    [2015]=>
    array(1) {
      ["01"]=>
      array(2) {
        ["city"]=>
        string(6) "Sydney"
        ["qty"]=>
        int(12)
      }
    }
  }
  [1]=>
  array(1) {
    [2015]=>
    array(1) {
      ["01"]=>
      array(2) {
        ["city"]=>
        string(6) "London"
        ["qty"]=>
        int(34)
      }
    }
  }
  [2]=>
  array(1) {
    [2015]=>
    array(1) {
      ["02"]=>
      array(2) {
        ["city"]=>
        string(6) "Sydney"
        ["qty"]=>
        int(56)
      }
    }
  }
}