Can someone help me with some code or instructions on how to walk recursively an array and when reaching the last element print the full path to it? A simple echo will work
I had similar problem. Here is a Depth-First Search-ish solution(no path depth included, it reaches until the very end of the array). Comment the 'if' statement if u don't want to include the value:
$output = array();
retrievePath($someArray, $output);
function retrievePath($someArray, array &$pathKeeper)
{
if(!is_array($someArray)){ // $someArray == "end"
$element = array_pop($pathKeeper) ?? '';// if the array is empty pop returns null, we don't want that
array_push($pathKeeper, $element . '->'. $someArray);
} else{
end($someArray);//we want to get the last element from the array so we move the internal pointer to it's end
$endElKey = key($someArray);//take the key where the pointer is
reset($someArray);
foreach($someArray as $key=>$value){
$element = array_pop($pathKeeper);
array_push($pathKeeper, $element === null ? $key : $element . '->' . $key);// we don't want '->' at the beginning
retrievePath($value, $pathKeeper);
if($key != $endElKey) //we check whether this is not the last loop
array_push($pathKeeper, $element);
}
}
}
I came up with the following function based on @salathe's one. It returns an array where each element is an array containing the leaf at index 0 and the array of the path keys at index 1:
function loosenMultiDimensionalArrayPathForEachVal($array) {
$iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array), \RecursiveIteratorIterator::SELF_FIRST);
$iterator->rewind();
$res = [];
foreach ($iterator as $v) {
$depth = $iterator->getDepth();
for ($path = array(), $i = 0, $z = $depth; $i <= $z; $i++) {
$path[] = $iterator->getSubIterator($i)->key();
}
$leaf = $array;
foreach ($path as $pathKey) {
$leaf = $leaf[$pathKey];
}
if (!is_array($leaf)) {
$res[] = [
$v,
$path
];
}
}
return $res;
}
The main reason I implemented this one is that $iterator->hasChildren()
returns true
if the current iterated leaf is an object. Therefore, I wouldn't be able to get the path of it that way.
You could employ a RecursiveIteratorIterator
(docs) to take the hard work out of recursing through the arrays.
function listArrayRecursive($someArray) {
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($someArray), RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $k => $v) {
$indent = str_repeat(' ', 10 * $iterator->getDepth());
// Not at end: show key only
if ($iterator->hasChildren()) {
echo "$indent$k :<br>";
// At end: show key, value and path
} else {
for ($p = array(), $i = 0, $z = $iterator->getDepth(); $i <= $z; $i++) {
$p[] = $iterator->getSubIterator($i)->key();
}
$path = implode(',', $p);
echo "$indent$k : $v : path -> $path<br>";
}
}
}