tags:

views:

620

answers:

5

Suppose I have an array in PHP that looks like this

array
(
   array(0)
   (
       array(0)
       (
         .
         . 
         .
       )

       .
       .
       array(10)
       (
         ..
       )
   )

   .
   . 
   .
   array(n)
   (

     array(0)
     (
     )
   )
 )

And I need all the leaf elements of this mulit-dimensional array into a linear array, how should I go about doing this without resorting recursion, such like this?

 function getChild($element)
 {

     foreach($element as $e)
     {

       if (is_array($e)
       {
          getChild($e);
       }
     }
 }

Note: code snippet above, horribly incompleted

Update: example of array

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [0] => Seller Object
                        (
                            [credits:private] => 5000000
                            [balance:private] => 4998970
                            [queueid:private] => 0
                            [sellerid:private] => 2
                            [dateTime:private] => 2009-07-25 17:53:10
                        )

                )

        )

...snipped.

[2] => Array
    (
        [0] => Array
            (
                [0] => Seller Object
                    (
                        [credits:private] => 10000000
                        [balance:private] => 9997940
                        [queueid:private] => 135
                        [sellerid:private] => 234
                        [dateTime:private] => 2009-07-14 23:36:00
                    )

            )

    ....snipped....

    )

)

+2  A: 

Try this:

function getLeafs($element) {
    $leafs = array();
    foreach ($element as $e) {
        if (is_array($e)) {
            $leafs = array_merge($leafs, getLeafs($e));
        } else {
            $leafs[] = $e;
        }
    }
    return $leafs;
}


Edit   Apparently you don’t want a recursive solution. So here’s an iterative solution that uses a stack:

function getLeafs($element) {
    $stack = array($element);
    $leafs = array();
    while ($item = array_pop($stack)) {
        while ($e = array_shift($item)) {
            if (is_array($e)) {
                array_push($stack, array($item));
                array_push($stack, $e);
                break;
            } else {
                $leafs[] = $e;
            }
        }
    }
    return $leafs;
}
Gumbo
A: 

There is no flatten function to get directly the leafs. You have to use recursion to check for each array if has more array children and only when you get to the bottom to move the element to a result flat array.

Elzo Valugi
+3  A: 

You could use iterators, for example:

$result = array();
foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array), RecursiveIteratorIterator::LEAVES_ONLY) as $value) {
    $result[] = $value;
}
Tom Haigh
+1, use more spl, http://php.net/spl
VolkerK
Is it okay to confirm with you if this works? I tried it but the loop never executes
Extrakun
I tested it with a simple array, and it does work, maybe you could post an example of the array you are using. I tried `$array = array( array('a', array( 'b','c','d', array('f'))), 'c' );`
Tom Haigh
Appreciate the help, I have updated my question with a live example. Does it matter that the leaf nodes are classes?
Extrakun
ah, i think the iterator will iterate through objects as if they are an array, so this probably won't work, sorry
Tom Haigh
+2  A: 

Use a stack:

<?php

$data = array(array(array("foo"),"bar"),"baz");

$results = array();
$process = $data;
while (count($process) > 0) {
    $current = array_pop($process);
    if (is_array($current)) {
        // Using a loop for clarity. You could use array_merge() here.
        foreach ($current as $item) {
            // As an optimization you could add "flat" items directly to the results array here.
            array_push($process, $item);
        }
    } else {
        array_push($results, $current);
    }
}

print_r($results);

Output:

Array
(
    [0] => baz
    [1] => bar
    [2] => foo
)

This should be more memory efficient than the recursive approach. Despite the fact that we do a lot of array manipulation here, PHP has copy-on-write semantics so the actual zvals of the real data won't be duplicated in memory.

Emil H
+5  A: 

Actually, there is a single function that will do the trick, check the manual page at: http://php.net/manual/en/function.array-walk-recursive.php

Quick snippet adapted from the page:

$data = array('test' => array('deeper' => array('last' => 'foo'), 'bar'), 'baz');

var_dump($data);

function printValue($value, $key, $userData) 
{
 //echo "$value\n";
 $userData[] = $value;
}


$result = new ArrayObject();
array_walk_recursive($data, 'printValue', $result);

var_dump($result);
jcinacio