views:

139

answers:

2

How can I recursively find the total value of all children of an array that looks something like this?

 [0] => Array
    (
        [value] => ? // 8590.25 + 200.5 + 22.4
        [children] => Array
            (
                [0] => Array
                    (
                        [value] => ? // 8590.25 + 200.5
                        [children] => Array
                            (
                                [0] => Array
                                    (
                                        [value] => 8590.25 // leaf node
                                    )
                                [1] => Array
                                    (
                                        [value] => 200.05 // leaf node
                                    )
                            )

                    )
                [1] => Array
                    (
                        [value] => 22.4 // leaf node
                    )
             )
    )
+1  A: 

This is the kind of case where I'd use a class instead of an array. That way, you can have a getValue () method (or use magic to define the value property using __get), that sums the child values on demand. If you have guarantees that things won't change after a point, you can cache those child sums to avoid repetetive computations. Maybe something like this?

class DataStructure
{
  private $children = array ();
  private $value = 0;

  public function __construct ($value = 0)
  {
    $this->value = $value;
  }

  public function getValue ()
  {
    $total = $this->value;
    foreach ($this->children as $child)
    {
      $total += $child->getValue ();
    }
    return $total;
  }

  public function addChild (DataStructure $child)
  {
    $this->children[] = $child;
  }
}
grossvogel
Interestingly enough, the tree is a RecursiveIterator (class DataStructure implements RecursiveIterator), and I'm trying to do the aggregation in a class that extends that DataStructure (class AggregateDatastructure extends DataStructure).. I've gotta look at this stuff some more.. :-P
Stephen J. Fuhry
Cool. Then I bet you can achieve this by just adding a method or two, once you sort out the details of your implementation. The idea is this: Instead of making one piece of code to iterate through all depths, just ask each child the same thing you've been asked, they'll turn around and ask their children...
grossvogel
+1  A: 

This will give you the total sum of the leaf node values:

$sum = 0;
array_walk_recursive($arr, create_function('$v, $k, $sum', '$sum[0] += $v;'), array(&$sum));

Equivalent using anonymous functions (PHP 5.3+):

$sum = 0;
array_walk_recursive($arr, function ($v) use (&$sum) { $sum += $v; });
nuqqsa