How to create a path based on array with multiple children - php

So, basically what i'm trying to do is getting combinations of the array children, for example i got the array:
[
"name" => "Item1",
"children" =>
[
"name" => "Item2",
"children" => [
["name" => "Item3"],
["name" => "Item4"]
]
],
["name" => "Item5"]
];
I tried to work with some functions i got on the stackoverflow, but i only got it to work with all of them at once, i was getting just
[
"Item4" => "Item1/Item2/Item4",
"Item5" => "Item1/Item5"
];
The output should be
[
"Item1" => "Item1",
"Item2" => "Item1/Item2",
"Item3" => "Item1/Item2/Item3"
"Item4" => "Item1/Item2/Item4"
"Item5" => "Item1/Item5"
];
As asked, the function i was working with before:
function flatten($arr) {
$lst = [];
/* Iterate over each item at the current level */
foreach ($arr as $key => $item) {
/* Get the "prefix" of the URL */
$prefix = $item['slug'];
/* Check if it has children */
if (array_key_exists('children', $item) and sizeof($item['children'])) {
/* Get the suffixes recursively */
$suffixes = flatten($item['children']);
/* Add it to the current prefix */
foreach($suffixes as $suffix) {
$url = $prefix . '/' . $suffix;
$lst[$item['id']] = $url;
}
} else {
/* If there are no children, just add the
* current prefix to the list */
$lst[$item['id']] = $prefix;
}
}
return $lst;
}

I've had to fix the data as the levels of data don't match up. The rest of the code is new as I found so many errors from your existing code.
Comments in code...
$data = [
"name" => "Item1",
"children" =>
[[
"name" => "Item2",
"children" =>[
["name" => "Item3"],
["name" => "Item4"]]
],
["name" => "Item5"]]
];
print_r(flatten($data));
function flatten($arr, $pathSoFar = '') {
$lst = [];
$path = $pathSoFar."/";
foreach ( $arr as $key => $value ) {
if ( $key === 'name' ) {
// Add name of current level onto path
$path .= $value;
$lst[$value] = $path;
}
else if ( $key === 'children' ) {
//Process child elements recursively and add into current array
$lst = array_merge($lst, flatten($value, $path));
}
else {
// This is for sub-elements which probably are (for example) 0, 1
// (removing trailing / to stop multiples)
$lst = array_merge($lst, flatten($value, rtrim($path,"/")));
}
}
return $lst;
}

Related

How to generate array path for specific key by looping through dynamic multidimensional array?

I have a dynamic multidimensional array as below:
$cityList = [
'AUS' => [
'VIC' => [
'population' => [ 'total' => '5M']
'Richmond' => [
'population' => [ 'total' => '0.15M']
]
],
'NSW' => [
'Carlton' => [
'population' => [ 'total' => '8M']
]
]
]
];
Here, the column population may or may not be present on all dimension. However, if it's present then it'll always have total as sub array as above.
Now, I need to traverse through the array and generate all path to population if exist.
I've written code as below:
public function fetchAllPopulation(array $cityList, $path = '', &$cityWithPopulation)
{
foreach ($cityList as $key => $city) {
if (is_array($city) && $key != 'population') {
$path .= $path == '' ? $key: "##$key";
$this->fetchAllPopulation($city, $path, $cityWithPopulation);
} else {
$population = $city['total'];
$cityWithPopulation[$path] = $population;
}
}
return $assetWithPathsAndIds;
}
Expected output:
[
'AUS##VIC' => '5M',
'AUS##VIC##Richmond' => '0.15M',
'AUS##NSW##Carlton' => '8M'
]
Actual output:
[
'AUS##VIC' => '5M',
'AUS##VIC##Richmond' => '0.15M',
'AUS##VIC##NSW##Carlton' => '8M' // this is incorrect
]
The problem is if any column has more than 2 dimensions, then the previous key will be appended on the next one as above.
Any feedback or correction to my code will be appreciated. Thanks!
This way:
public function fetchAllPopulation(array $cityList, $path, &$cityWithPopulation)
{
foreach ($cityList as $key => $city) {
if (is_array($city) && $key != 'population') {
$subPath = $path . ($path == '' ? $key: "##$key");
$this->fetchAllPopulation($city, $subPath, $cityWithPopulation);
} else {
$population = $city['total'];
$cityWithPopulation[$path] = $population;
}
}
return $assetWithPathsAndIds;
}

How to get the same key and different value in nested array php

I have this post and get method inside the child.
$array1 = [
"attribute" => "MySchool",
"child" =>
[
"method" => "GET",
"child" => [
"attribute" => "school",
"child" => [
[
"attribute" => "harvard"
],
],
],
],
[
"method" => "POST",
"child" => [
"attribute" => "school",
"child" => [
[
"attribute" => "stanford"
],
],
],
],
]
$array2 = array(
0 => "GET"
1 => "school"
2 => "harvard"
);
Now I just want the method get and its attribute value.
So I want a result of array just like this:
array(
0 => "MySchool"
1 => "get"
2 => "school"
3 => "harvard"
)
Here is the snippet for you,
/**
* Function to fetch array with type
*
* #param array $array The array
* #param string $slug The slug
*
* #return array custom array
*/
function custom($array, $slug)
{
$res = [];
if (is_array($array)) {
// default attribute I assign to result as first attribute
$res[] = $array['attribute'];
foreach ($array['child'] as $k => $v) {
if ($v['method'] == $slug) {
$res[] = strtolower($v['method']);
array_walk_recursive($v['child'], function ($item, $k1) use (&$res) {
if ($k1 == 'attribute') {
$res[] = $item;
}
});
}
}
}
return $res;
}
$slug = 'GET';
$temp = custom($array1, $slug);
print_r($temp);
$slug = 'POST';
$temp = custom($array1, $slug);
Demo
Output for GET:
Array
(
[0] => MySchool
[1] => get
[2] => school
[3] => harvard
)
For post
Array
(
[0] => MySchool
[1] => post
[2] => school
[3] => stanford
)
You can check if the key value of 'method' is GET then extract the elements you need.
$result = [];
foreach ($array1 as $key => $value) {
if ($key === 'attribute') $result[] = $value;
if ($key === 'child' && $value['method'] === 'GET') {
$result[] = $value['method'];
$result[] = $array1['child']['child']['attribute'];
$result[] = $array1['child']['child']['child'][0]['attribute'];
}
}
print_r($result);
/*
* Output:
* Array
* (
* [0] => MySchool
* [1] => GET
* [2] => school
* [3] => harvard
* )
*/
If the response is always in the same format.
You can format the array with this code :
$result = [
$array1["attribute"],
$array1["child"]["method"],
$array1["child"]["attribute"]
$array1["child"]["child"]["attribute"]
];
Try the following:
$result = getArray($array1);
function getArray($array, $new_array = [])
{
$result = [];
foreach ($array as $key => $value) {
if ($key === 'attribute'
|| $key === 'method') {
$new_array[] = $value;
}
}
if (isset($array['child'])
&& is_countable($array['child'])
&& !isset($array['child'][0])
) {
getArray($array['child'], $new_array);
}
elseif(isset($array['child'][0])) {
getArray($array['child'][0], $new_array);
} else {
return print_r($new_array);
}
}

How to create dynamic combination with php?

I have 3 array like
$arr = [
"color" => [["name"=>"red"]],
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]]
]
$combo = array();
foreach ($arr['size'] as $size) {
foreach($arr['color'] as $color){
foreach ($arr['type'] as $type) {
$variant = json_encode(['size' => $size->name, 'color' =>
$color->name, 'type' => $type->name]);
array_push($combo,$variant);
}
}
}
echo $combo;
// result
0 => "{"size":"15 inch","color":"yellow","type":"metal"}"
1 => "{"size":"18 inch","color":"yellow","type":"plastic"}"
It works properly but but there is can be less or more variants. How can I handle this.
For example
$arr = [
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]]
]
Or
$arr = [
"color" => [["name"=>"red"]],
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]],
"brand" => [['name' => 'something']],
]
For what i understand, you have to combine the arrays of properties into one array of
object.
I have to leave now, but if you need a explanation leave a comment and i updated the answers
$arr = [
"color" => [["name"=>"red"],['name'=>'yellow']],
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]],
"brand" => [['name' => 'something']],
];
function runFor($arr ,&$array, $keys,$index,&$positions){
foreach ($arr[$keys[$index]] as $key => $espec){
$positions[$keys[$index]] = $key;
if($index + 1 < count($keys)){
runFor($arr,$array,$keys, $index+1,$positions);
}else{
$item = (object)[];
foreach ($keys as $key){
$item->$key = $arr[$key][$positions[$key]]['name'];
}
array_push($array,$item);
}
unset($positions[$keys[$index]]);
}
}
$array = array();
$keys = array_keys($arr);
$positions = [];
runFor($arr,$array,$keys,0,$positions);
$combo = array();
foreach ($array as $item){
array_push($combo,json_encode($item));
}
var_dump($combo);

Multidimensional array to text using only keys

I have an array of this sort:
$array = [
"Darren" => [
"age" => "18",
"work" => [
"occupation" => "developer",
"company" => "ABC Ltd"
]
],
"John" => [
"age" => "24",
"work" => [
"occupation" => "developer",
"company" => "ABC Ltd",
"url" => "www.example.com"
],
]
]
And would like to merge the keys with a dot in between, depending on the array's hierachy:
"Darren.age"
"Darren.work.occupation"
"Darren.work.company"
...
The function that I made so far is
public function buildExpressionKey($array, $parentKey = null){
$expression = [];
foreach($array as $key=>$value){
if(is_array($value)){
array_push($expression, $parentKey. implode(".",
$this->buildExpressionKey($value, $key)));
}else{
array_push($expression, $key);
}
}
return $expression;
}
it is returning this value at the moment:
[
[0] => "age.Darrenoccupation.company"
[1] => "age.Johnoccupation.company.url"
]
Was wondering if it is possible to make a function which automatically does merges the keys like that, thanks in advance :)
What you are currently asking for:
<?php
$people =
[
'John' =>
[
'Occupation' => 'Developer',
'Age' => 18
],
'Darren' =>
[
'Occupation' => 'Manager',
'Age' => 40
]
];
foreach($people as $name => $value)
foreach($value as $k => $v)
$strings[] = $name . '.' . $k;
var_export($strings);
Output:
array (
0 => 'John.Occupation',
1 => 'John.Age',
2 => 'Darren.Occupation',
3 => 'Darren.Age',
)
Managed to resolve this issue :)
/**
* #param $array
* #return array
*/
public function buildExpressionKey($array){
$iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array));
$keys = array();
foreach ($iterator as $key => $value) {
// Build long key name based on parent keys
for ($i = $iterator->getDepth() - 1; $i >= 0; $i--) {
$key = $iterator->getSubIterator($i)->key() . '.' . $key;
}
$keys[] = $key;
}
return $keys;
}
Found something similar on here: Get array's key recursively and create underscore separated string

Search for matching subarray in parent or child of a multidimensional array

I have the following multidimensional array to build a dynamic menu:
[
"3gnitjUdm6" => [
"name" => "Overview",
"slug" => "overview",
"priority" => 1,
"pages" => [
"i3OQlLqgqO" => [
"name" => "Dashboard",
"url" => "",
"priority" => 2,
"subpages" => [],
],
"izma1tvjGd" => [
"name" => "Settings",
"url" => "/settings",
"priority" => 4,
"subpages" => [],
]
]
],
"IcSujiIx9A" => [
"name" => "Content",
"slug" => "content",
"priority" => 5,
"pages" => [
"3KJdhtCRuI" => [
"name" => "Users",
"url" => "/users",
"priority" => 2,
"subpages" => [],
],
"M3zw9hq6rW" => [
"name" => "Pets",
"url" => "/pets",
"priority" => 4,
"subpages" => [],
],
],
],
]
Each section contains an array of pages, and each page can contain an array of subpages. I need to be able to search through this array to find the key of the section using a key and value pair.
private function _find_section($key, $value) {
foreach($this->menu as $section_key => $section) {
if(is_array($section[$key])) {
foreach($section[$key] as $sub_key => $sub) {
if($sub_key === $value) {
return $section_key;
}
}
} elseif(is_string($section[$key])) {
if($section[$key] === $value) {
return $section_key;
}
} else {
return false;
}
}
}
Running the following code:
_find_section('name', 'Content')
Always returns false.
function flatten(array $collection, array $nested_keys = []) {
$output = [];
foreach ($collection as $key => $value) {
foreach ($nested_keys as $nested_key) {
if (isset($value[$nested_key]) && is_array($value[$nested_key])) {
$output = array_merge($output, flatten($value[$nested_key], [$nested_key]));
}
}
$output[$key] = $value;
}
return $output;
}
function column(array $collection, string $key) {
return array_combine(
array_keys($collection),
array_map(function ($row) use ($key) { return $row[$key]; }, $collection)
);
}
function find_section(array $menu, string $key, string $value) {
$set = column(flatten($menu, ['pages', 'subpages']), $key);
return array_search($value, $set);
}
var_dump(find_section($menu, 'name', 'Dashboard')); // string(10) "i3OQlLqgqO"
You might want to try doing a recursive function instead and forego hardcoded foreach() loops, then you can easily search through many levels of your array using this method:
function recurseFind($array,$findK,$findV,$last=false)
{
if(is_object($array))
$array = (array) $array;
foreach($array as $key => $value) {
if($key == $findK && $value == $findV)
return $last;
if(is_array($value))
$doFind = recurseFind($value,$findK,$findV,$key);
if(!empty($doFind))
return $doFind;
}
}
print_r(recurseFind($arr,'name','Dashboard'));
Gives you:
i3OQlLqgqO

Categories