5
\$\begingroup\$

I have a multidimensional array as a result from a webservice called from PHP. I cannot edit the webservice, but the result is as

array (size=5)
  'id' => int 0
  'name' => 
    array (size=7)
      'it' => string 'Tutti' (length=5)
      'ca' => string 'Tots' (length=4)
      'es' => string 'Todos' (length=5)
      'de' => string 'Alle' (length=4)
      'fr' => string 'Tous' (length=4)
      'nl' => string 'Alle' (length=4)
      'en' => string 'All' (length=3)
  'tree' => 
    array (size=0)
      empty
  'languages' => 
    array (size=7)
  'subTypes' => 
    array (size=4)
      0 => 
        array (size=5)
          'id' => int 1
          'name' => 
            array (size=29)
              ...
          'tree' => 
            array (size=1)
              ...
          'languages' => 
            array (size=29)
              ...
          'subTypes' => 
            array (size=3)
              ...
      1 => 
        array (size=5)
          'id' => int 2
          'name' => 
            array (size=29)
              ...
          'tree' => 
            array (size=1)
              ...
          'languages' => 
            array (size=29)
             ...
          'subTypes' => 
            array (size=6)
              ...

As you can see, you can interpret it as a multidimensional array of objects. Each objects can have child objects of same type.

My goal is to get only the elements on a specific language, fe en (and thus rest is not taken). I thought to use a recursive function.

// filter array
function getByKey($array, $search, $level, $valuesUsed) {
    echo '<ul>';
    foreach($array as $key => $value) {
        if(is_array($array[$key])) {
            $valuesUsed = getByKey($array[$key], $search, $level + 1, $valuesUsed);
        } else if ($key === $search) {
            if(!in_array($value, $valuesUsed)) {
                echo "<li> $key = $value </li>";
                $valuesUsed[] = $value;
            }
        }
    }
    echo '</ul>';
    return $valuesUsed;
}

Then I call the above function from my HTML template by

<div id="foo">
    <?php
        getByKey($routeTypes, 'en', 0, array());
    ?>
</div>

$routeTypes is the array, obtained from the webservice. It works as expected, it results as the list here below, which I can wrap with a js library.

<ul>
   <li>this is level1</li>
   <li>this is level1</li>
   <li>
       <ul>
           <li>this is level 2</li>
           <li>this is level 2</li>
           <li>
               ... level++
           </li>
       </ul>
   </li>
</ul>

Now, I'm questioning myself if this can be improved ? It doesn't take long to have a list from a large multidimensional array. (a simple print_r command resulted in 45000+ characters).

Especially checking the $valuesUsed array, to prevent duplicates (yes the webservice has objects which contains child keys which is similar to level - 2 parent (or on other level ...... ))

Each time I am running through the lower levels, I am looping through the $valuesUsed array. Is there not a better way to loop through the sublevels ? Maybe an array_walk() or array_walk_recursive() with a callback function ?

\$\endgroup\$
3
  • \$\begingroup\$ Is this complete code ? It's seems to be missing some part ? Does it work on it's own ? Are you here for a review or something else ? \$\endgroup\$
    – Marc-Andre
    Mar 20, 2014 at 14:03
  • \$\begingroup\$ yes, i'm here for a review. Just asking if the recursive function can be improved. The above function will be called in the HTML template. (it displays the list of which i want on the webpage). Edited my post. \$\endgroup\$
    – KarelG
    Mar 20, 2014 at 14:09
  • \$\begingroup\$ I was asking to come up with a title. The title of your question should describe what your code do! \$\endgroup\$
    – Marc-Andre
    Mar 20, 2014 at 14:16

1 Answer 1

1
\$\begingroup\$

You can choose a (key => value) pair recursively with this function:

function array_value_recursive($key, array $arr){
    $val = array();
    array_walk_recursive($arr, function($v, $k) use($key, &$val){
        if($k == $key) array_push($val, $v);
    });
    return count($val) > 1 ? $val : array_pop($val);
}

This function makes use of array_walk_recursive() to push into a placeholder array whatever value is pointed to by whichever key matches our needle key.

Proof code:

$array = array(
    'id' => 0,
    'name' => array(
        'it' => 'Tutti',
        'ca' => 'Tots',
        'es' => 'Todos', 
        'de' => 'Alle' ,
        'fr' => 'Tous',
        'nl' => 'Alle',
        'en' => 'All'
    ),
    'languages' => array(
        "d" => 33
    ),
    'subTypes' => array(
        0 => array(
            'id' => 1,
            'name' => array(
                'it' => 'Tutti',
                'ca' => 'Tots',
                'es' => 'Todos', 
                'de' => 'Alle' ,
                'fr' => 'Tous',
                'nl' => 'Alle',
                'en' => 'All'
            )
        ),
        1 => array(
            'id' => 1,
            'name' => array(
                'it' => 'Tutti',
                'ca' => 'Tots',
                'es' => 'Todos', 
                'de' => 'Alle' ,
                'fr' => 'Tous',
                'nl' => 'Alle',
                'en' => 'All'
            )
        ),
        2 => array(
            'id' => 1,
            'name' => array(
                'it' => 'Tutti',
                'ca' => 'Tots',
                'es' => 'Todos', 
                'de' => 'Alle' ,
                'fr' => 'Tous',
                'nl' => 'Alle',
                'en' => 'All'
            )
        )
    )
);

print_r(array_value_recursive("de", $array));

The above test code, which seeks all "de" keys, will output:

Array ( 
    [0] => Alle 
    [1] => Alle 
    [2] => Alle 
    [3] => Alle
)
\$\endgroup\$
1
  • \$\begingroup\$ thanks for your suggestion, but yours code didn't kept the child level of the main array. The goal is to get a nested list (menu - submenu) as mentioned in my post. \$\endgroup\$
    – KarelG
    Mar 24, 2014 at 8:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.