tags:

views:

354

answers:

2

This is actually a problem that I've already solved, but I suspect that there may be a better solution. I have a nested array which basically represents a list of all the nodes from a category tree (in no particular order):

Array(
    [0] => Array(
        [Category] => Array(
            [id] => 49
            [name] => Poster
        )
        [Child] => Array()
    )
    [1] => Array(
        [Category] => Array(
            [id] => 48
            [name] => Sticker
        )
        [Child] => Array()
    )
    [2] => Array(
        [Category] => Array(
            [id] => 46
            [name] => Hat
        )
        [Child] => Array()
    )
    [3] => Array(
        [Category] => Array(
            [id] => 45
            [name] => Hoodie
        )
        [Child] => Array()
    )
)

You'll notice that $node['Child'] is an empty array in all instances. This is because I've already used array_filter() to filter out all non-leaf-nodes. Still, what I ultimately want is to have a single-dimensional array of the leaf nodes like this:

Array(
    [49] => Poster
    [48] => Sticker
    [46] => Hat
    [45] => Hoodie
)

So what would be the most elegant way of converting the first array to the second array?

Optionally, you can also start with an array of both leaf-nodes and non-leaf-nodes, and try to both prune the array and restructure it. An example of a non-leaf-node would be something like:

[7] => Array(
    [Category] => Array(
        [id] => 36
        [name] => Merch
    )
    [Child] => Array(
        [0] => Array(
            [id] => 49
            [name] => Poster
        )
        [1] => Array(
            [id] => 48
            [name] => Sticker
        )
        [2] => Array(
            [id] => 40
            [name] => Apparel
        )
    )
)

Lastly, I'm using CakePHP, so use of CakePHP's Set class is also acceptable.

+3  A: 

Elegant? Define elegant. I think some people are going to turn this into a golf contest as opposed to simply doing what makes sense and is evident to anyone stumbling upon the code later on:

$cats = array();
foreach($categories as $c) {
    $cats[$c['Category']['id']] = $c['Category']['name'];
}

I suspect this is what you have, in which case I suggest you pat yourself in the back and move on.

Paolo Bergantino
The simple solution is often the best. You could use for instead of foreach. But both are correct.
OIS
+1  A: 

This answer is not in anyway intended to be "elegant", but I suppose it might fall under the "clever" category. (Note: clever solutions are not always "good" solutions)

preg_match_all( "/\"name\";s:\d+:\"(.*?)\"/i", serialize( $arr ), $matches );

print_r( $matches[1] );

In all honesty, recursive iteration is the best choice for clarity, even if it's not terribly efficient or concise.

$arr = array(
    "0" => array(
        "Category" => array(
            "id" => 49
            ,"name" => Poster
        )
        ,"Child" => array()
    )
    ,"1" => array(
        "Category" => array(
            "id" => 48
            ,"name" => Sticker
        )
        ,"Child" => array()
    )
    ,"2" => array(
        "Category" => array(
            "id" => 46
            ,"name" => Hat
        )
        ,"Child" => array()
    )
    ,"3" => array(
        "Category" => array(
            "id" => 45
            ,"name" => Hoodie
        )
        ,"Child" => array(
            "0" => array(
                "id" => 49
                ,"name" => Poster
            )
            ,"1" => array(
                "id" => 48
                ,"name" => Sticker
            )
            ,"2" => array(
                "id" => 40
                ,"name" => Apparel
            )
        )
    )
);

findNames( $arr, $names );
echo '<pre>';
print_r( $names );
echo '</pre>';

function findNames( $source, &$out )
{
    foreach ( $source as $value )
    {
     if ( isset( $value['name'] ) )
     {
      // Assumes that if $value['name'] exists, $value['id'] must also exist
      $out[$value['id']] = $value['name'];
      continue;
     }
     if ( is_array( $value ) )
     {
      findNames( $value, &$out );
     }
    }
}
Peter Bailey