Andres Ramos
Andres Ramos

Reputation: 330

How to make recursive function to calculate averages of values in multi-dimensional arrays

How can I loop recursively through the following multi-dimensional array but still calculate the average by Standards? Here is my initial array, then find my code (Looping through each level which is not ideal) and then the Output.

I'm looking for a function that can reduce or improve this code so I can re-utilize to calculate the average for the other levels.

Array
(
    [42715] => Array
        (
            [1886] => Array
                (
                    [1252] => Array
                        (
                            [1016] => Array
                                (
                                    [Standard 1] => Array
                                        (
                                            [0] => 1.0000000
                                            [1] => 0.5000000
                                            [2] => 1.0000000
                                            [3] => 1.0000000
                                            [4] => 1.0000000
                                            [5] => 1.0000000
                                        )

                                    [1] => 10/24/2017
                                    [Standard 2] => Array
                                        (
                                            [0] => 1.0000000
                                            [1] => 1.0000000
                                            [2] => 1.0000000
                                        )

                                    [Standard 3] => Array
                                        (
                                            [0] => 0.0000000
                                            [1] => 0.0000000
                                            [2] => 0.0000000
                                        )

                                    [Standard 4] => Array
                                        (
                                            [0] => 1.0000000
                                            [1] => 1.0000000
                                            [2] => 1.0000000
                                        )

                                    [Standard 5] => Array
                                        (
                                            [0] => 1.0000000
                                            [1] => 1.0000000
                                            [2] => 0.0000000
                                        )

                                    [Standard 6] => Array
                                        (
                                            [0] => 0.0000000
                                            [1] => 1.0000000
                                            [2] => 1.0000000
                                            [3] => 0.0000000
                                            [4] => 1.0000000
                                            [5] => 1.0000000
                                        )

                                    [Standard 7] => Array
                                        (
                                            [0] => 1.0000000
                                            [1] => 1.0000000
                                            [2] => 1.0000000
                                        )

                                    [Standard 8] => Array
                                        (
                                            [0] => 0.0000000
                                            [1] => 1.0000000
                                            [2] => 0.0000000
                                        )

                                    [Standard 9] => Array
                                        (
                                            [0] => 0.0000000
                                            [1] => 0.0000000
                                            [2] => 0.0000000
                                        )

                                )

                            [1019] => Array
                                (
                                    [Standard 8] => Array
                                        (
                                            [0] => 1.0000000
                                            [1] => 0.0000000
                                            [2] => 0.0000000
                                            [3] => 1.0000000
                                            [4] => 0.0000000
                                            [5] => 0.0000000
                                            [6] => 0.0000000
                                        )

                                    [1] => 10/24/2017
                                )

                            [1017] => Array
                                (
                                    [Standard 1] => Array
                                        (
                                            [0] => 0.0000000
                                        )

                                    [1] => 10/24/2017
                                    [Standard 2] => Array
                                        (
                                            [0] => 1.0000000
                                            [1] => 0.0000000
                                        )

                                    [Standard 3] => Array
                                        (
                                            [0] => 0.0000000
                                            [1] => 0.0000000
                                        )

                                    [Standard 4] => Array
                                        (
                                            [0] => 1.0000000
                                        )

                                    [Standard 5] => Array
                                        (
                                            [0] => 0.0000000
                                        )

                                    [Standard 6] => Array
                                        (
                                            [0] => 0.0000000
                                        )

                                    [Standard 7] => Array
                                        (
                                            [0] => 1.0000000
                                        )

                                    [Standard 8] => Array
                                        (
                                            [0] => 0.0000000
                                        )

                                    [Standard 9] => Array
                                        (
                                            [0] => 1.0000000
                                        )

                                )

                        )

                )

I'm calculating the average of 9 Standards with the following code.

$quizrow = array();
foreach ($modulet as $teacherid => $teacherlist) {
    foreach ($teacherlist as $classid => $classlist) {
        foreach ($classlist as $courseid => $quizlist) {
            foreach ($quizlist as $quizid => $stdlist) {

                $count = $total = 0;
                $timemodified   = $stdlist['timemodified'];

                // Remove this element so we only have Standards.
                unset($stdlist['timemodified']);

                // Reorder the array so we get Standard 1, Standard 2, etc...
                ksort($stdlist, 2);
                foreach ($stdlist as $name => $std) {
                    $quizrow[$teacherid][$classid][$courseid][$quizid][0] = btr_get_quiz_name($quizid);
                    $quizrow[$teacherid][$classid][$courseid][$quizid][1] = $timemodified;
                    $quizrow[$teacherid][$classid][$courseid][$quizid][2] = "";

                    // Calculate the average of the Standards.
                    $average = round(array_sum($std) / count($std) * 100, 1) . "%";
                    $quizrow[$teacherid][$classid][$courseid][$quizid][$name] = $average;
                    $total += $average;
                    $count++;
                }

                // The second index will hold the average results for all Standards.
                $quizrow[$teacherid][$classid][$courseid][$quizid][2] = round($total / $count, 1) . "%";
            }
        }
    }
}

OUTPUT:

Array
(
    [42715] => Array
        (
            [1886] => Array
                (
                    [1252] => Array
                    (
                        [1016] => Array
                            (
                                [0] => Name
                                [1] => 10/24/2017
                                [2] => 62%
                                [Standard 1] => 91.7%
                                [Standard 2] => 100%
                                [Standard 3] => 0%
                                [Standard 4] => 100%
                                [Standard 5] => 66.7%
                                [Standard 6] => 66.7%
                                [Standard 7] => 100%
                                [Standard 8] => 33.3%
                                [Standard 9] => 0%
                            )

                        [1019] => Array
                            (
                                [0] => Name
                                [1] => 10/24/2017
                                [2] => 58.7%
                                [Standard 8] => 28.6%
                            )

                        [1017] => Array
                            (
                                [0] => Name
                                [1] => 10/24/2017
                                [2] => 49.3%
                                [Standard 1] => 0%
                                [Standard 2] => 50%
                                [Standard 3] => 0%
                                [Standard 4] => 100%
                                [Standard 5] => 0%
                                [Standard 6] => 0%
                                [Standard 7] => 100%
                                [Standard 8] => 0%
                                [Standard 9] => 100%
                            )

                    )

            )

EDIT UPDATE: The Output array is being organized again, to calculate its average for the next level.

Array
(
    [42715] => Array
        (
            [1886] => Array
                (
                    [1252] => Array
                        (
                            [0] => Array
                                (
                                    [0] => Name
                                    [1] => Name
                                    [2] => Name
                                )

                            [1] => Array
                                (
                                    [0] => 10/24/2017
                                    [1] => 10/24/2017
                                    [2] => 10/24/2017
                                )

                            [2] => Array
                                (
                                    [0] => 62%
                                    [1] => 58.7%
                                    [2] => 49.3%
                                )

                            [Standard 1] => Array
                                (
                                    [0] => 91.7%
                                    [1] => 0%
                                )

                            [Standard 2] => Array
                                (
                                    [0] => 100%
                                    [1] => 50%
                                )

                            [Standard 3] => Array
                                (
                                    [0] => 0%
                                    [1] => 0%
                                )

                            [Standard 4] => Array
                                (
                                    [0] => 100%
                                    [1] => 100%
                                )

                            [Standard 5] => Array
                                (
                                    [0] => 66.7%
                                    [1] => 0%
                                )

                            [Standard 6] => Array
                                (
                                    [0] => 66.7%
                                    [1] => 0%
                                )

                            [Standard 7] => Array
                                (
                                    [0] => 100%
                                    [1] => 100%
                                )

                            [Standard 8] => Array
                                (
                                    [0] => 33.3%
                                    [1] => 28.6%
                                    [2] => 0%
                                )

                            [Standard 9] => Array
                                (
                                    [0] => 0%
                                    [1] => 100%
                                )

                        )

                )

I'm looping again with foreach to the deepest level with a pretty much similar code get the average output:

Array
(
    [42715] => Array
        (
            [1886] => Array
                (
                    [1252] => Array
                        (
                            [0] => Unit of Study: The Price of Fashion – 830L
                            [1] => 10/24/2017
                            [2] => 50.9%
                            [Standard 1] => 45.9%
                            [Standard 2] => 75%
                            [Standard 3] => 0%
                            [Standard 4] => 100%
                            [Standard 5] => 33.4%
                            [Standard 6] => 33.4%
                            [Standard 7] => 100%
                            [Standard 8] => 20.6%
                            [Standard 9] => 50%
                        )

                )

I have to do this until the latest level.

Upvotes: 1

Views: 100

Answers (2)

mickmackusa
mickmackusa

Reputation: 47894

[see inline comments for explanation of processes]

Code: (Demo)

function recursive_calculator($array){
    foreach($array as $id=>&$elem){  // make every level modifiable
        if(!isset($elem['timemodified'])){
            $elem=recursive_calculator($elem);  // I am using timemodified to indicate whether there are scores to process
        }else{
            $elem[0]='Quiz Name'; // btr_get_quiz_name($id);
            $elem[1]=$elem['timemodified'];  // store date with a new key
            unset($elem['timemodified']);    // remove old element
            $score_sets=array_filter($elem,function($k){return strpos($k,'Standard ')===0;},ARRAY_FILTER_USE_KEY);  // isolate quiz score subarrays only
            foreach($score_sets as $name=>$scores){
                $elem[$name]=($averages[]=round(array_sum($scores)/count($scores)*100,1))."%"; // double declaration, $averages will be used outside of the loop
            }
            $elem[2]=round(array_sum($averages)/count($averages),1)."%";  // calculate the cumulative average for all sets/quizzes
            ksort($elem,SORT_NATURAL);  // sort the data as desired
        }
    }
    return $array;  // return the full modified data structure
}

$modulet=[
    42715=>[
        1886=>[
            1295=>[
                1166=>[
                    'Standard 1'=>[0.5000000,0.5000000,1.0000000,0.5000000,0.5000000,0.5000000,0.5000000,0.5000000,0.5000000,0.5000000,0.5000000],
                    'timemodified'=>'10/23/2017',
                    'Standard 2'=>[0.0000000,1.0000000,1.0000000,1.0000000,0.0000000,0.0000000,0.0000000,0.0000000,1.0000000,0.0000000,0.0000000]
                ]
            ]
        ]
    ]
];

var_export(recursive_calculator($modulet));

Output:

array (
  42715 => 
  array (
    1886 => 
    array (
      1295 => 
      array (
        1166 => 
        array (
          0 => 'Quiz Name',
          1 => '10/23/2017',
          2 => '45.5%',
          'Standard 1' => '54.5%',
          'Standard 2' => '36.4%',
        ),
      ),
    ),
  ),
)

Upvotes: 1

Felipe Valdes
Felipe Valdes

Reputation: 2217

If you only need the value, for the whole array, and don't care about the indexes, you can do this:

 <?php                                                                      
    $a = array(array(array(array(array(1,2,3,4,5,99)))));                      
    $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a));       
    $s = array();                                                              
    foreach($it as $v) {                                                       
      $s[] = $v;                                                               
    }                                                                          
    echo(array_sum($s)/count($s));                                             

See: How to Flatten a Multidimensional Array?

Upvotes: 0

Related Questions