I’am stuck on assigning pid’s (parent id’s) on 3rd element. I mean in setParent()
if I return $array
before call recursive function, then I see that “PC” and “Laptop” are having correct pid’s.
If I run all script, then I get $newArr
is null
. PHP 7.3, Laravel 6.
I want to make this:
[ ['pc', ['pc',null, null] ,'id'=>1,'pid'=>1], ['laptop', ['pc','laptop', null] ,'id'=>2,'pid'=>1], ['acc', ['pc','acc', null] ,'id'=>3,'pid'=>1], ['bags', ['pc','acc', 'bags'] ,'id'=>4,'pid'=>3], ['adapter', ['pc','acc', 'adapter'] ,'id'=>5,'pid'=>3], ['clothes', ['clothes',null,null] ,'id'=>6,'pid'=>6] ];
From that :
function test3(){ $array = [ ['pc', ['pc',null, null] ,'id'=>1,'pid'=>0], ['laptop', ['pc','laptop', null] ,'id'=>2,'pid'=>0], ['acc', ['pc','acc', null] ,'id'=>3,'pid'=>0], ['bags', ['pc','acc', 'bags'] ,'id'=>4,'pid'=>0], ['adapter', ['pc','acc', 'adapter'] ,'id'=>5,'pid'=>0], ['clothes', ['clothes',null,null] ,'id'=>6,'pid'=>0] ]; $newArr = $this->setParent($array); return response()->json([$newArr]); } function setParent($array, $goStop='go'){ if($goStop == 'go'){ $foundPids = 0; foreach($array as $k => $v){ if( $v["pid"] == 0) $foundPids++; } if( $foundPids == 0){ return $this->setParent($array, 'stop'); // or return $array; } // parent search foreach($array as $k1 => $v1){ if ($v1['pid']!=0) break; $keyInd = array_search($v1[0] , $v1[1]);// $v1 looks like {"0":"pc","1":["pc",null,null],"id":1,"pid":0} if($keyInd == 0){ $array[$k1]['pid'] = $v1['id']; // PC updated } if($keyInd > 0){ $parentName = $v1[1][$keyInd-1]; $IdToWriteInPid = 0; foreach ($array as $k1inner => $v1inner){ if($v1inner[$keyInd-1] == $parentName){ $IdToWriteInPid = $v1inner['id']; } } $array[$k1]['pid'] = $IdToWriteInPid; // Laptop updated // // if uncomment, then i see that category PC having pid 1 // and category Laptop having pid 1. It is ok. // // return $array; // return $this->setParent($array, 'go' ); } } } else return $array; }
Advertisement
Answer
You could build hierarchy paths for each of your entries using implode
, then make use of array_reduce
to:
- index your entries by their path,
- alter the
pid
of each subsequent entry if their parent’s path was found.
Finally, array_values
will switch back your array’s indexes to numerical format.
Note: this assumes the parents are always defined before their children, like in your sample data.
Note 2: this also assumes the names such as 'pc'
cannot contain forward slashes (/
). Feel free to change the separator otherwise.
function fillParentIds(array $input): array { return array_values(array_reduce($input, static function (array $entriesByPath, array $entry): array { $hierarchy = array_filter($entry[1]); $pathToParent = implode('/', array_slice($hierarchy, 0, -1)); $pathToEntry = implode('/', $hierarchy); $entry['pid'] = array_key_exists($pathToParent, $entriesByPath) ? $entriesByPath[$pathToParent]['id'] : $entry['id']; $entriesByPath[$pathToEntry] = $entry; return $entriesByPath; }, [])); }
Usage:
$withParentIds = fillParentIds($input);
Demo: https://3v4l.org/DeORi