Gábor DANI
Gábor DANI

Reputation: 2135

How to count multidimensional array values?

I am building an MLM software in PHP, one of its function is to count the downline performance. It creates an array from parent-child relationships, which can be seen below. How can I get the performance (array key: points) of my children, and their grandchildren as well through the fifth down level?

    Array
(
    [children] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [name] => Medvedev
                    [email] => 
                    [points] => 7
                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [id] => 3
                                    [name] => Putin
                                    [email] => 
                                    [points] => 4
                                    [children] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [id] => 5
                                                    [name] => Nathan
                                                    [email] => 
                                                    [points] => 3
                                                )

                                            [1] => Array
                                                (
                                                    [id] => 7
                                                    [name] => George
                                                    [email] => 
                                                    [points] => 666
                                                )

                                        )

                                )

                            [1] => Array
                                (
                                    [id] => 4
                                    [name] => Lucas
                                    [email] => 
                                    [points] => 43
                                )

                        )

                )
        )

    [id] => 27
    [name] => Boss
    [email] => 
    [points] => 99999
)

Upvotes: 3

Views: 3994

Answers (2)

Harald Brinkhof
Harald Brinkhof

Reputation: 4455

In my opinion this calls for recursion because you'll do the same thing over each flat level of the array: add the points.

so you'll need to

  • loop over each array
  • add points found
  • if we find any children, do it again but with children array

while keeping track of levels and jumping out if you reach your limit

With that in mind I thought of the following solution:

<?php

$values = array();

//first
$values[] = array('name'=>'andrej','points'=>1,'children'=>array());
$values[] = array('name'=>'peter','points'=>2,'children'=>array());
$values[] = array('name'=>'mark','points'=>3,'children'=>array());

//second
$values[0]['children'][] = array('name'=>'Sarah','points'=>4,'children'=>array());
$values[2]['children'][] = array('name'=>'Mike','points'=>5,'children'=>array());

//third 
$values[0]['children'][0]['children'][] = array('name'=>'Ron','points'=>6,'children'=>array());

//fourth
$values[0]['children'][0]['children'][0]['children'][] = array('name'=>'Ronny','points'=>7,'children'=>array());

//fifth
$values[0]['children'][0]['children'][0]['children'][0]['children'][] = array('name'=>'Marina','points'=>10,'children'=>array());

//sixth
$values[0]['children'][0]['children'][0]['children'][0]['children'][0]['children'][] = array('name'=>'Pjotr','points'=>400,'children'=>array());


function collect_elements($base, $maxLevel,$child='children',$gather='points', &$catch = array(), $level = 0) {
/*    I pass $catch by reference so that all recursive calls add to the same array
      obviously you could use it straight away but I return the created array as well
  because I find it to be cleaner in PHP (by reference is rare and can lead to confusion)

  $base = array it works on
  $maxLevel = how deep the recursion goes

  $child = key of the element where you hold your possible childnodes
      $gather = key of the element that has to be collected
*/

  $level++;
  if($level > $maxLevel) return; // we're too deep, bail out

  foreach ($base as $key => $elem) {
    // collect the element if available
    if(isset($elem[$gather])) $catch[] = $elem[$gather];

    /*
    does this element's container have children? 
       [$child] needs to be set, [$child] needs to be an array, [$child] needs to have elements itself
    */
    if (isset($elem[$child]) && is_array($elem[$child]) && count($elem[$child])){
       // if we can find another array 1 level down, recurse that as well  
       collect_elements($elem[$child],$maxLevel,$child,$gather, $catch,$level); 
    }
  }
return $catch;
}

print array_sum(collect_elements($values,5)) . PHP_EOL;

collect_elements will collect the element you're interested in (until maximum depth is reached) and append it to a flat array, so that you can act on it upon return. In this case we do an array_sum to get the total of poins collected

Only the first for parameters are interesting:

collect_elements($base, $maxLevel,$child='children',$gather='points'

not optional: $base is the array to work on $maxLevel is the maximum depth the function needs to descend into the arrays optional: $child defines the key of the element that contains the children of current element (array) $gather defines the key of the element that contains what we want to gather

The remaining parameters are just ones used for recursion

Upvotes: 1

Luca Filosofi
Luca Filosofi

Reputation: 31173

this should work with unlimited depth starting from a main array like

$array = array(
    'children' => array( /* ADD HERE INFINITE COMBINATION OF CHILDREN ARRAY */ ),
    'id' => #,
    'name' => '',
    'email' => '',
    'points' => #
);

function recursive_children_points($arr) {
    global $hold_points;
    if (isset($arr['points'])) {
        $hold_points[] = $arr['points'];
    }
    if (isset($arr['children'])) {
        foreach ($arr['children'] as $children => $child) {
            recursive_children_points($child);
        }
    }
    return $hold_points;
}

$points = recursive_children_points($array);
print "<pre>";
print_r($points);
/**
     // OUTPUT
     Array
(
    [0] => 99999
    [1] => 7
    [2] => 4
    [3] => 3
    [4] => 666
    [5] => 43
)
**/
    print "<pre>";

Upvotes: 3

Related Questions