用点符号键将多维数组转换为二维数组。

时间:2022-04-30 10:44:24

There are plenty of tips and code examples out there of accessing PHP arrays with dot notation, but I would like to do somewhat the opposite. I would like to take a multidimensional array like this:

有很多使用点符号访问PHP数组的技巧和代码示例,但是我想做一些相反的事情。我想取一个这样的多维数组:

$myArray = array(
    'key1' => 'value1',
    'key2' => array(
        'subkey' => 'subkeyval'
    ),
    'key3' => 'value3',
    'key4' => array(
        'subkey4' => array(
            'subsubkey4' => 'subsubkeyval4',
            'subsubkey5' => 'subsubkeyval5',
        ),
        'subkey5' => 'subkeyval5'
    )
);

And turn it into this (likely through some recursive function):

然后把它变成这个(很可能是通过递归函数)

$newArray = array(
    'key1'                    => 'value1',
    'key2.subkey'             => 'subkeyval',
    'key3'                    => 'value3',
    'key4.subkey4.subsubkey4' => 'subsubkeyval4',
    'key4.subkey5.subsubkey5' => 'subsubkeyval5',
    'key4.subkey5'            => 'subkeyval5'
);

6 个解决方案

#1


62  

teh codez

格兰codez

$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($myArray));
$result = array();
foreach ($ritit as $leafValue) {
    $keys = array();
    foreach (range(0, $ritit->getDepth()) as $depth) {
        $keys[] = $ritit->getSubIterator($depth)->key();
    }
    $result[ join('.', $keys) ] = $leafValue;
}

output

输出

Array
(
    [key1] => value1
    [key2.subkey] => subkeyval
    [key3] => value3
    [key4.subkey4.subsubkey4] => subsubkeyval4
    [key4.subkey4.subsubkey5] => subsubkeyval5
    [key4.subkey5] => subkeyval5
)

demo: http://codepad.org/YiygqxTM

演示:http://codepad.org/YiygqxTM

I need to go, but if you need an explanation of that tomorrow, ask me.

我得走了,但如果你明天需要解释的话,可以问我。

#2


4  

This will handle an arbitrary level of nesting:

这将处理任意级别的嵌套:

<? //PHP 5.4+
$dotFlatten = static function(array $item, $context = '') use (&$dotFlatten){
    $retval = [];
    foreach($item as $key => $value){
        if (\is_array($value) === true){
            foreach($dotFlatten($value, "$context$key.") as $iKey => $iValue){
                $retval[$iKey] = $iValue;
            }
        } else {
            $retval["$context$key"] = $value;
        }
    }
    return $retval;
};

var_dump(
    $dotFlatten(
        [
            'key1' => 'value1',
            'key2' => [
                'subkey' => 'subkeyval',
            ],
            'key3' => 'value3',
            'key4' => [
                'subkey4' => [
                    'subsubkey4' => 'subsubkeyval4',
                    'subsubkey5' => 'subsubkeyval5',
                ],
                'subkey5' => 'subkeyval5',
            ],
        ]
    )
);
?>

#3


2  

There is already the answer with RecursiveIteratorIterator. But here is a more optimal solution, that avoids using nested loops:

使用recursiveiterator迭代器已经有了答案。但这里有一个更优的解决方案,避免使用嵌套循环:

$iterator = new RecursiveIteratorIterator(
    new RecursiveArrayIterator($arr),
    RecursiveIteratorIterator::SELF_FIRST
);
$path = [];
$flatArray = [];

foreach ($iterator as $key => $value) {
    $path[$iterator->getDepth()] = $key;

    if (!is_array($value)) {
        $flatArray[
            implode('.', array_slice($path, 0, $iterator->getDepth() + 1))
        ] = $value;
    }
}

There are several points need to be made here. Notice the use of RecursiveIteratorIterator::SELF_FIRST constant here. It is important as the default one is RecursiveIteratorIterator::LEAVES_ONLY which wouldn't let us access all keys. So with this constant set, we start from the top level of an array and go deeper. This approach lets us store the history of keys and prepare the key when we rich leaf using RecursiveIteratorIterator::getDepth method.

这里有几点需要说明。注意这里使用了RecursiveIteratorIterator::SELF_FIRST常量。它很重要,因为默认值是RecursiveIteratorIterator::LEAVES_ONLY,它不允许我们访问所有的键。在这个常数集合中,我们从数组的顶层开始深入。这种方法允许我们在使用RecursiveIteratorIterator::getDepth方法丰富leaf时存储键的历史并准备键。

Here is a working demo.

这是一个工作演示。

#4


1  

This is my take on a recursive solution, which works for arrays of any depth:

这是我对递归解决方案的看法,它适用于任何深度的数组:

function convertArray($arr, $narr = array(), $nkey = '') {
    foreach ($arr as $key => $value) {
        if (is_array($value)) {
            $narr = array_merge($narr, convertArray($value, $narr, $nkey . $key . '.'));
        } else {
            $narr[$nkey . $key] = $value;
        }
    }

    return $narr;
}

Which can be called as $newArray = convertArray($myArray).

它可以被称为$newArray = convertArray($myArray)。

#5


0  

You could do it like this, but chris's answer should be preferred:

你可以这样做,但是克里斯的答案应该是:

<?php 
$array = array();
foreach($myArray as $key=>$value){
    //1st level
    if(is_array($value)){
        //2nd level
        foreach($value as $key_b=>$value_b){
            //3rd level
            if(is_array($value_b)){
                foreach($value_b as $key_c=>$value_c){
                    $array[$key.'.'.$key_b.'.'.$key_c]=$value_c;
                }
            }else{
                $array[$key.'.'.$key_b]=$value_b;
            }
        }
    }else{
        $array[$key]=$value;
    }
}

print_r($array);
/*
Array
(
[key1] => value1
[key2.subkey] => subkeyval
[key3] => value3
[key4.subkey4.subsubkey4] => subsubkeyval4
[key4.subkey4.subsubkey5] => subsubkeyval5
[key4.subkey5] => subkeyval5
)
*/

#6


0  

This another approach similar to Blafrat above - but handles simply arrays as values.

这是另一种类似于上面的Blafrat的方法——但只将数组作为值来处理。

 function dot_flatten($input_arr, $return_arr = array(), $prev_key = '')
 {
     foreach ($input_arr as $key => $value)
     {
        $new_key = $prev_key . $key;

        // check if it's associative array 99% good
        if (is_array($value) && key($value) !==0 && key($value) !==null)
        {
            $return_arr = array_merge($return_arr, dot_flatten($value, $return_arr, $new_key . '.'));
        }
        else
        {
            $return_arr[$new_key] = $value;
        }
    }

    return $return_arr;
}

(The only case this wouldn't catch is where you had a value that was associative but the first key was 0.)

(唯一的例子是,你的值是关联的,但第一个键是0。)

Note that the RecursiveIteratorIterator can be slower than regular recursive function. https://xenforo.com/community/threads/php-spl-why-is-recursiveiteratoriterator-100x-slower-than-recursive-search.57572/

注意,递归veiterator可能比常规递归函数慢。https://xenforo.com/community/threads/php - spl -为什么- - recursiveiteratoriterator - 100 x -慢-比search.57572/——递归

In this case using the sample array given for 1000 iterations php5.6, this code is twice as fast (recursive=.032 vs interator=.062) - but the difference is probably insignificant for most cases. Mainly I prefer recursive because I find the logic of the Iterator needlessly complicated for a simple use case like this.

在本例中,使用为1000次迭代php5.6提供的示例数组,该代码的速度是原来的两倍(recursive=)。032 vs interator=.062) -但这种差异在大多数情况下可能并不明显。主要是我喜欢递归,因为我发现迭代器的逻辑对于这样一个简单的用例来说是不必要的复杂。

#1


62  

teh codez

格兰codez

$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($myArray));
$result = array();
foreach ($ritit as $leafValue) {
    $keys = array();
    foreach (range(0, $ritit->getDepth()) as $depth) {
        $keys[] = $ritit->getSubIterator($depth)->key();
    }
    $result[ join('.', $keys) ] = $leafValue;
}

output

输出

Array
(
    [key1] => value1
    [key2.subkey] => subkeyval
    [key3] => value3
    [key4.subkey4.subsubkey4] => subsubkeyval4
    [key4.subkey4.subsubkey5] => subsubkeyval5
    [key4.subkey5] => subkeyval5
)

demo: http://codepad.org/YiygqxTM

演示:http://codepad.org/YiygqxTM

I need to go, but if you need an explanation of that tomorrow, ask me.

我得走了,但如果你明天需要解释的话,可以问我。

#2


4  

This will handle an arbitrary level of nesting:

这将处理任意级别的嵌套:

<? //PHP 5.4+
$dotFlatten = static function(array $item, $context = '') use (&$dotFlatten){
    $retval = [];
    foreach($item as $key => $value){
        if (\is_array($value) === true){
            foreach($dotFlatten($value, "$context$key.") as $iKey => $iValue){
                $retval[$iKey] = $iValue;
            }
        } else {
            $retval["$context$key"] = $value;
        }
    }
    return $retval;
};

var_dump(
    $dotFlatten(
        [
            'key1' => 'value1',
            'key2' => [
                'subkey' => 'subkeyval',
            ],
            'key3' => 'value3',
            'key4' => [
                'subkey4' => [
                    'subsubkey4' => 'subsubkeyval4',
                    'subsubkey5' => 'subsubkeyval5',
                ],
                'subkey5' => 'subkeyval5',
            ],
        ]
    )
);
?>

#3


2  

There is already the answer with RecursiveIteratorIterator. But here is a more optimal solution, that avoids using nested loops:

使用recursiveiterator迭代器已经有了答案。但这里有一个更优的解决方案,避免使用嵌套循环:

$iterator = new RecursiveIteratorIterator(
    new RecursiveArrayIterator($arr),
    RecursiveIteratorIterator::SELF_FIRST
);
$path = [];
$flatArray = [];

foreach ($iterator as $key => $value) {
    $path[$iterator->getDepth()] = $key;

    if (!is_array($value)) {
        $flatArray[
            implode('.', array_slice($path, 0, $iterator->getDepth() + 1))
        ] = $value;
    }
}

There are several points need to be made here. Notice the use of RecursiveIteratorIterator::SELF_FIRST constant here. It is important as the default one is RecursiveIteratorIterator::LEAVES_ONLY which wouldn't let us access all keys. So with this constant set, we start from the top level of an array and go deeper. This approach lets us store the history of keys and prepare the key when we rich leaf using RecursiveIteratorIterator::getDepth method.

这里有几点需要说明。注意这里使用了RecursiveIteratorIterator::SELF_FIRST常量。它很重要,因为默认值是RecursiveIteratorIterator::LEAVES_ONLY,它不允许我们访问所有的键。在这个常数集合中,我们从数组的顶层开始深入。这种方法允许我们在使用RecursiveIteratorIterator::getDepth方法丰富leaf时存储键的历史并准备键。

Here is a working demo.

这是一个工作演示。

#4


1  

This is my take on a recursive solution, which works for arrays of any depth:

这是我对递归解决方案的看法,它适用于任何深度的数组:

function convertArray($arr, $narr = array(), $nkey = '') {
    foreach ($arr as $key => $value) {
        if (is_array($value)) {
            $narr = array_merge($narr, convertArray($value, $narr, $nkey . $key . '.'));
        } else {
            $narr[$nkey . $key] = $value;
        }
    }

    return $narr;
}

Which can be called as $newArray = convertArray($myArray).

它可以被称为$newArray = convertArray($myArray)。

#5


0  

You could do it like this, but chris's answer should be preferred:

你可以这样做,但是克里斯的答案应该是:

<?php 
$array = array();
foreach($myArray as $key=>$value){
    //1st level
    if(is_array($value)){
        //2nd level
        foreach($value as $key_b=>$value_b){
            //3rd level
            if(is_array($value_b)){
                foreach($value_b as $key_c=>$value_c){
                    $array[$key.'.'.$key_b.'.'.$key_c]=$value_c;
                }
            }else{
                $array[$key.'.'.$key_b]=$value_b;
            }
        }
    }else{
        $array[$key]=$value;
    }
}

print_r($array);
/*
Array
(
[key1] => value1
[key2.subkey] => subkeyval
[key3] => value3
[key4.subkey4.subsubkey4] => subsubkeyval4
[key4.subkey4.subsubkey5] => subsubkeyval5
[key4.subkey5] => subkeyval5
)
*/

#6


0  

This another approach similar to Blafrat above - but handles simply arrays as values.

这是另一种类似于上面的Blafrat的方法——但只将数组作为值来处理。

 function dot_flatten($input_arr, $return_arr = array(), $prev_key = '')
 {
     foreach ($input_arr as $key => $value)
     {
        $new_key = $prev_key . $key;

        // check if it's associative array 99% good
        if (is_array($value) && key($value) !==0 && key($value) !==null)
        {
            $return_arr = array_merge($return_arr, dot_flatten($value, $return_arr, $new_key . '.'));
        }
        else
        {
            $return_arr[$new_key] = $value;
        }
    }

    return $return_arr;
}

(The only case this wouldn't catch is where you had a value that was associative but the first key was 0.)

(唯一的例子是,你的值是关联的,但第一个键是0。)

Note that the RecursiveIteratorIterator can be slower than regular recursive function. https://xenforo.com/community/threads/php-spl-why-is-recursiveiteratoriterator-100x-slower-than-recursive-search.57572/

注意,递归veiterator可能比常规递归函数慢。https://xenforo.com/community/threads/php - spl -为什么- - recursiveiteratoriterator - 100 x -慢-比search.57572/——递归

In this case using the sample array given for 1000 iterations php5.6, this code is twice as fast (recursive=.032 vs interator=.062) - but the difference is probably insignificant for most cases. Mainly I prefer recursive because I find the logic of the Iterator needlessly complicated for a simple use case like this.

在本例中,使用为1000次迭代php5.6提供的示例数组,该代码的速度是原来的两倍(recursive=)。032 vs interator=.062) -但这种差异在大多数情况下可能并不明显。主要是我喜欢递归,因为我发现迭代器的逻辑对于这样一个简单的用例来说是不必要的复杂。