-
-
Save SeanCannon/6585889 to your computer and use it in GitHub Desktop.
<?php | |
/** | |
* Convert a multi-dimensional array into a single-dimensional array. | |
* @author Sean Cannon, LitmusBox.com | [email protected] | |
* @param array $array The multi-dimensional array. | |
* @return array | |
*/ | |
function array_flatten($array) { | |
if (!is_array($array)) { | |
return false; | |
} | |
$result = array(); | |
foreach ($array as $key => $value) { | |
if (is_array($value)) { | |
$result = array_merge($result, array_flatten($value)); | |
} else { | |
$result = array_merge($result, array($key => $value)); | |
} | |
} | |
return $result; | |
} |
@brandonmcconnell Thanks! Your answer is exactly what i was looking for!
Working with associative arrays:
/**
* flatten function
*
* @param array $multiDimArray
* @return array
*/
function flatten(array $multiDimArray): array
{
$localFlatten = [];
foreach ($multiDimArray as $key => $value) {
if (\is_array($value)) {
foreach (flatten($value) as $subKey => $subValue) {
$localFlatten[$subKey] = $subValue;
}
continue;
}
$localFlatten[$key] = $value;
}
return $localFlatten;
}
Using
flatten([['abc' => 123, 'a' => 1, 'abc'], [2 => 'zxc']]);
// Result:
[
"abc" => 123,
"a" => 1,
0 => "abc",
2 => "zxc",
]
Here is what I was looking for:
function true_flatten(array $array, array $parents = [])
{
$return = [];
foreach ($array as $k => $value) {
$p = empty($parents) ? [$k] : [...$parents, $k];
if (is_array($value)) {
$return = [...$return, ...true_flatten($value, $p)];
} else {
$return[implode('_', $p)] = $value;
}
}
return $return;
}
Sample array:
$r = [
'a' => 'value1',
'b' => [
'c' => 'value1.1',
'd' => 'value1.2',
],
'e' => 'value2',
'f' => [
'j' => [
'k' => 'value2.1',
'm' => 'value2.2',
'n' => 'value2.3',
],
],
'o' => 'value3',
'p' => [
'some' => [
'very' => [
'deep' => [
'item' => [
'first',
'second',
]
]
]
]
],
'q' => 'value5',
]; // sample data
Output:
{
"a": "value1",
"b_c": "value1.1",
"b_d": "value1.2",
"e": "value2",
"f_j_k": "value2.1",
"f_j_m": "value2.2",
"f_j_n": "value2.3",
"o": "value3",
"p_some_very_deep_item_0": "first",
"p_some_very_deep_item_1": "second",
"q": "value5"
}
Nice @graceman9, but it doesn't work in PHP 7, as unpacking arrays with string keys was only implemented in PHP 8.
Fatal error: Uncaught Error: Cannot unpack array with string keys
Ref: https://wiki.php.net/rfc/array_unpacking_string_keys
I just changed ...
with array_merge
to make your code compatible with older versions of PHP.
function true_flatten(array $array, array $parents = [])
{
$return = [];
foreach ($array as $k => $value) {
$p = empty($parents) ? [$k] : array_merge($parents, [$k]);
if (is_array($value)) {
$return = array_merge($return, true_flatten($value, $p));
} else {
$return[implode('_', $p)] = $value;
}
}
return $return;
}
Output:
Array
(
[a] => value1
[b_c] => value1.1
[b_d] => value1.2
[e] => value2
[f_j_k] => value2.1
[f_j_m] => value2.2
[f_j_n] => value2.3
[o] => value3
[p_some_very_deep_item_0] => first
[p_some_very_deep_item_1] => second
[q] => value5
)
Tested in PHP 7.4.9
@sayhicoelho Have you tried my approach above? It should work with associative and non-associative arrays, and be compatible with PHP 7+.
It also supports a depth parameter, so you can easily flatten only the top layer, the first N layers, or infinitely.
@brandonmcconnell Using my sample data it gives not what I expected.
By the way, how to use it with unlimited $depth? array_flatten($r, 999)
doesn't look good for me
Despite of that your function does the job of flattening, no doubt :) maybe flatten is not the right word because of ambiguity?
@sayhicoelho thanks for 7.x support!
echo json_encode(array_flatten($r, 9));
{
"a": "value1",
"c": "value1.1",
"d": "value1.2",
"e": "value2",
"k": "value2.1",
"m": "value2.2",
"n": "value2.3",
"o": "value3",
"0": "first",
"1": "second",
"q": "value5"
}
@graceman9 What data produces an unexpected result?
For infinite depth, just use -1
@brandonmcconnell Have you noticed the difference?
{
"a": "value1",
"b_c": "value1.1",
}
and
{
"a": "value1",
"c": "value1.1",
}
@graceman9 Oh you want the keys to be concatenated, so every key keeps the log of its original path. Yeah, you are correct that my version does not do that. I tried to follow the approach common in other languages. 🙂
For a simple 2D array:
$multiDimArray = [[1, 2], [3, 4], [5, 6]];
$flatArray = array_reduce($multiDimArray, 'array_merge', []);
@georgeholt @ultrasamad @cliffordp I made a slight alteration to George's
array_flatten()
function to support a$depth
parameter. With this parameter, the function will only flatten to the depth specified, or to the default$depth
value when the argument is not used.For my example here, I am using a default
$depth
of1
, similar to JavaScript, however, you could change the default$depth
to-1
which will work virtually the same as usingarray.flat(Infinity)
in JavaScript, since negative values are truthy in PHP.Here is an example using the sample array data Clifford posted earlier in this thread. I am using JSON encoding for returned values for readability:
Here's a simpler example, using a non-associative array, returns again presented with JSON-encoded for readability.