Reputation: 488
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;
}
Upvotes: 0
Views: 208
Reputation: 14927
You could build hierarchy paths for each of your entries using implode
, then make use of array_reduce
to:
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
Upvotes: 1