michael
michael

Reputation: 308

return all keys of nested array

given a nested array of arbitrary depth like this:

$array = array(
            1400=> 
                array(7300=>
                        array(
                            7301=> array(),
                            7302=> array(),
                            7305=> array(
                                7306=>array()
                            ),
                        ),
                    7314=>array()
                ),
            );

how would one get the hierarchy of keys for any key.

for example:

getkeys(7305);

should return 1400,7300,7305 in that order

or

getkeys(7314);

should return 1400,7314

all array keys are unique values

Upvotes: 2

Views: 350

Answers (3)

rkmax
rkmax

Reputation: 18135

Using RecursiveIteratorIterator

$array = array(
  1400 => array(
    7300 => array(
      7301=> array(),
      7302 => array(),
      7305 => array(
        7306=>array()
      ),
    ),
    7314=>array()
  ),
);

function getKeys($key, $array) {
  $found_path = [];
  $ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($array), RecursiveIteratorIterator::SELF_FIRST);

  foreach ($ritit as $leafValue) {

    $path = array();
    foreach (range(0, $ritit->getDepth()) as $depth) {
      $path[] = $ritit->getSubIterator($depth)->key();
    }

    if (end($path) == $key) {
      $found_path = $path;
      break;
    }
  }

  return $found_path;
}

print_r(getKeys(7305, $array));
// Array
// (
//     [0] => 1400
//     [1] => 7300
//     [2] => 7305
// )

Upvotes: 2

Max Zuber
Max Zuber

Reputation: 1229

The idea is to check current array branch, and if the needle key isn't found, then iterate current items and check their array child nodes by recursive function calls. Before each step down we push a current key to stack, and pop the stack if the function does not found a needle key in whole branch. So if the key found, the function returns true by the chain, preserving successful keys in the stack.

function branchTraversing(& $branch, & $key_stack, $needle_key) {
  $found = false;
  if (!array_key_exists($needle_key, $branch)) {
    reset($branch);
    while (!$found && (list($key, $next_branch) = each($branch))) {
      if (is_array($next_branch)) {
        array_push($key_stack, $key);
        $found = branchTraversing($next_branch, $key_stack, $needle_key);
        if (!$found) {
          array_pop($key_stack);
        }
      }
    }
  } else {
    array_push($key_stack, $needle_key);
    $found = true;
  }

  return $found;
}

function getPath(& $array, $needle_key) {
  $path = [];
  branchTraversing($array, $path, $needle_key);
  return $path;
}

$test_keys = [1400, 7300, 7302, 7306, 7314, 666];

foreach ($test_keys as $search_key) {
  echo '<p>' . $search_key . ' => [ '
  . implode(', ', getPath($array, $search_key)) . ' ]</p>';
}

Upvotes: 1

Standej
Standej

Reputation: 753

This is very interesting problem you have so I tried to make a function that will echo your keys. If this is not good enough pls let me know I can improve code. Thanks.

<?php

$a = array(
            1400=> 
                array(7300=>
                        array(
                            7301=> array(),
                            7302=> array(),
                            7305=> array(
                                7306=>array()
                            ),
                        ),
                    7314=>array()
                ),
            );

$mykey = 7306;
$level = 0;
$result = array();
$resultarray = test($a,$mykey,$level,$result);

function test($array,$mykey,$level,$result){
    $level++;
    foreach($array as $key => $element){
        if($key == $mykey){
            echo 'found';
            print_r($result);
            exit;
        } else if(is_array($element)){
            $result[$level] = $key;
            $result1 = test($element,$mykey,$level,$result);
        }
    }
}

Upvotes: 1

Related Questions