Reputation: 330
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
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
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