I have a multidimensional array that goes many layers deep:
$columns=[
'id',
'snippet'=>[
'publishedAt',
'channelId',
'channelTitle',
'description',
'thumbnails'=>[
'default'=>['url','width','height'],
'medium'=>['url','width','height'],
'high'=>['url','width','height'],
'standard'=>['url','width','height'],
'maxres'=>['url','width','height']
],
'tags',
'categoryId'
],
'status'=>[
'uploadStatus',
'privacyStatus',
'license',
'embeddable',
'publicStatsViewable',
'madeForKids'
],
'statistics'=>[
'viewCount',
'likeCount',
'favoriteCount',
'commentCount'
]
];
I need to change the above array to resemble:
[id] => 1
[snippet_publishedAt] => 1
[snippet_channelId] => 1
[snippet_channelTitle] => 1
[snippet_description] => 1
[snippet_thumbnails_default_url] => 1
[snippet_thumbnails_default_width] => 1
[snippet_thumbnails_default_height] => 1
[snippet_thumbnails_medium_url] => 1
[snippet_thumbnails_medium_width] => 1
[snippet_thumbnails_medium_height] => 1
[snippet_thumbnails_high_url] => 1
[snippet_thumbnails_high_width] => 1
[snippet_thumbnails_high_height] => 1
[snippet_thumbnails_standard_url] => 1
[snippet_thumbnails_standard_width] => 1
[snippet_thumbnails_standard_height] => 1
[snippet_thumbnails_maxres_url] => 1
[snippet_thumbnails_maxres_width] => 1
[snippet_thumbnails_maxres_height] => 1
[snippet_tags] => 1
[snippet_categoryId] => 1
[status_uploadStatus] => 1
[status_privacyStatus] => 1
[status_license] => 1
[status_embeddable] => 1
[status_publicStatsViewable] => 1
[status_madeForKids] => 1
[statistics_viewCount] => 1
[statistics_likeCount] => 1
[statistics_favoriteCount] => 1
[statistics_commentCount] => 1
I've been using:
$renamed=[];
foreach($columns as $key1=>$item1){
if(is_array($item1)){
foreach($item1 as $key2=>$item2){
if(is_array($item2)){
foreach($item2 as $key3=>$item3){
if(is_array($item3)){
foreach($item3 as $key4=>$item4){
if(is_array($item4)){
}else{$renamed[$key1.'_'.$key2.'_'.$key3.'_'.$item4]=1;}
}
}else{$renamed[$key1.'_'.$key2.'_'.$item3]=1;}
}
}
else{$renamed[$key1.'_'.$item2]=1;}
}
}else{$renamed[$item1]=1;}
}
print_r($renamed);
But this is limited to only a few levels. I'd like it to be infinitely able to generate a result regardless of how many levels the original array has. Is there a recursive version of my code? I've been trying to figure one out without success. My problem is, when I create a function to generate a recursive result, the return itself needs to passed on to enable the next recursion but I have no idea what to pass on to the next iteration while generating my ideal result.
CodePudding user response:
This is doable. Something like this:
function simplify($columns, $root = '')
{
$output = [];
$root .= ($root == '' ? '' : '-');
foreach ($columns as $key => $value) {
if (is_array($value)) {
$output = array_merge($output, simplify($value, $root . $key));
} else {
$output[$root . $value] = 1;
}
}
return $output;
}
var_export(simplify($columns));
Here's a working example.
To answer your question: There's not much to "pass on". All that is needed is to keep track of the current "root" of an sub-array and merge all the results into one big array.
I just thought of a slight improvement:
function simplify($columns, $root = '')
{
$output = [];
foreach ($columns as $key => $value) {
if (is_array($value)) {
$output = array_merge($output, simplify($value, $root . $key . '-'));
} else {
$output[$root . $value] = 1;
}
}
return $output;
}
And here's a working example.
CodePudding user response:
Here's my take. Pretty much similar to other answers.
$columns = [
'id',
'snippet' => [
'publishedAt',
'channelId',
'channelTitle',
'description',
'thumbnails' => [
'default' => ['url', 'width', 'height'],
'medium' => ['url', 'width', 'height'],
'high' => ['url', 'width', 'height'],
'standard' => ['url', 'width', 'height'],
'maxres' => ['url', 'width', 'height'],
],
'tags',
'categoryId',
],
'status' => [
'uploadStatus',
'privacyStatus',
'license',
'embeddable',
'publicStatsViewable',
'madeForKids',
],
'statistics' => [
'viewCount',
'likeCount',
'favoriteCount',
'commentCount',
],
];
function flatten($arr, $parents = []) {
$result = [];
foreach ($arr as $key => $value) {
$me = $parents;
if (is_array($value)) {
$me[] = $key;
$result = array_merge($result, flatten($value, $me));
} else {
$me[] = $value;
$result[implode("_", $me)] = 1;
}
}
return $result;
}
$result = flatten($columns);
print_r($result);
Output:
Array
(
[id] => 1
[snippet_publishedAt] => 1
[snippet_channelId] => 1
[snippet_channelTitle] => 1
[snippet_description] => 1
[snippet_thumbnails_default_url] => 1
[snippet_thumbnails_default_width] => 1
[snippet_thumbnails_default_height] => 1
[snippet_thumbnails_medium_url] => 1
[snippet_thumbnails_medium_width] => 1
[snippet_thumbnails_medium_height] => 1
[snippet_thumbnails_high_url] => 1
[snippet_thumbnails_high_width] => 1
[snippet_thumbnails_high_height] => 1
[snippet_thumbnails_standard_url] => 1
[snippet_thumbnails_standard_width] => 1
[snippet_thumbnails_standard_height] => 1
[snippet_thumbnails_maxres_url] => 1
[snippet_thumbnails_maxres_width] => 1
[snippet_thumbnails_maxres_height] => 1
[snippet_tags] => 1
[snippet_categoryId] => 1
[status_uploadStatus] => 1
[status_privacyStatus] => 1
[status_license] => 1
[status_embeddable] => 1
[status_publicStatsViewable] => 1
[status_madeForKids] => 1
[statistics_viewCount] => 1
[statistics_likeCount] => 1
[statistics_favoriteCount] => 1
[statistics_commentCount] => 1
)