Sum current month value with previous last 5 month value in array

I have an array with some values. Here I need to make a calculation for Year 2019 only.

``````\$array = array(
"date_2019_12" => 0,
"date_2019_11" => 0,
"date_2019_10" => 0,
"date_2019_09" => 0,
"date_2019_08" => 0,
"date_2019_07" => 0,
"date_2019_06" => 0,
"date_2019_05" => 0,
"date_2019_04" => 0,
"date_2019_03" => 0,
"date_2019_02" => 0,
"date_2019_01" => 10,
"date_2018_12" => 1,
"date_2018_11" => 2,
"date_2018_10" => 3,
"date_2018_09" => 4,
"date_2018_08" => 5,
"date_2018_07" => 6,
);

krsort(\$array);
``````

From this array, I need to calculate the sum of previous five months & current month starting "date_2019_01".

That means I need final array result like below:

``````"date_2019_01" => 25(10+1+2+3+4+5)
"date_2019_02" => 20(0+10+1+2+3+4)
"date_2019_03" => 16(0+0+10+1+2+3)
"date_2019_04" => 13(0+0+0+10+1+2)
... until "date_2019-12".
``````

I have spend many times finding solution but I could not. Can anybody help me?

I have tried following code and somewhere now I am lost.

``````\$newArr = array();
foreach(\$array as \$key => \$val) {
\$explode = explode("_", \$key);
\$value = (int)\$explode[2];
for(\$i = 0; \$i <= 5; \$i++) {
\$newArr[\$array[\$explode[0].'_'.\$explode[1].'_'.\$value]] = \$array[\$explode[0].'_'.\$explode[1].'_'.\$value];
\$value--;
}
}
``````

This code will do what you want. It uses a nested loop to iterate over each month and the 5 preceding months, creating a sum for each one from the different date values in the array:

``````\$year = 2019;
\$sums = array();
for (\$i = 1; \$i <= 12; \$i++) {
\$sum = 0;
for (\$j = \$i - 5; \$j <= \$i; \$j++) {
\$y = \$year;
\$m = \$j;
if (\$m <= 0) {
\$m += 12;
\$y -= 1;
}
\$date = sprintf("date_%4d_%02d", \$y, \$m);
\$sum += \$array[\$date];
}
\$date = sprintf("date_%4d_%02d", \$year, \$i);
\$sums[\$date] = \$sum;
}
print_r(\$sums);
``````

Output:

``````Array (
[date_2019_01] => 25
[date_2019_02] => 20
[date_2019_03] => 16
[date_2019_04] => 13
[date_2019_05] => 11
[date_2019_06] => 10
[date_2019_07] => 0
[date_2019_08] => 0
[date_2019_09] => 0
[date_2019_10] => 0
[date_2019_11] => 0
[date_2019_12] => 0
)
``````

Demo on 3v4l.org

You don't need to nest the loops, you can use one loop, array_slice and array_sum.

``````krsort(\$array);

\$year = "2019";
\$keys = array_keys(\$array); //save keys since we use array_values in the loop
foreach(array_values(\$array) as \$k => \$v){
// If the year is found in the key slice out the next six item and sum them
if(strpos(\$keys[\$k], \$year) !== false) \$res[\$keys[\$k]] = array_sum(array_slice(\$array, \$k, 6));
}
var_dump(\$res);
``````

https://3v4l.org/LSQRg

• You should adapt your code to show 2018 values as well. – Andrei Lupuleasa Apr 19 at 8:03
• @AndreiLupuleasa OP only wanted data for 2019 – Nick Apr 19 at 8:06
• As Nick says, OP wants to be able to select year (I believe). – Andreas Apr 19 at 8:12
• Fair enough but your code wont work in 2020 because your using magic numbers. Anyway nice solution `array_sum` is fater than `foreach` and better to use. – Andrei Lupuleasa Apr 19 at 8:13
• @AndreiLupuleasa why wouldn't my code work in 2020? What magic number? – Andreas Apr 19 at 8:33
``````        \$newArr = array();
foreach(\$array as \$key => \$val) {
\$i=1;
\$newArr[\$key] = \$val;
foreach(\$array as \$key2 => \$val2){
if(\$key>\$key2 && \$i <= 5){
\$newArr[\$key] += \$val2;
\$i++;
}
}
}

array(18) {
["date_2019_12"]=>
int(0)
["date_2019_11"]=>
int(0)
["date_2019_10"]=>
int(0)
["date_2019_09"]=>
int(0)
["date_2019_08"]=>
int(0)
["date_2019_07"]=>
int(0)
["date_2019_06"]=>
int(10)
["date_2019_05"]=>
int(11)
["date_2019_04"]=>
int(13)
["date_2019_03"]=>
int(16)
["date_2019_02"]=>
int(20)
["date_2019_01"]=>
int(25)
["date_2018_12"]=>
int(21)
["date_2018_11"]=>
int(20)
["date_2018_10"]=>
int(18)
["date_2018_09"]=>
int(15)
["date_2018_08"]=>
int(11)
["date_2018_07"]=>
int(6)
}
``````

There are two steps I have performed.

Step 1: Sorting custom format array by keys

``````// sort the array first by date of given format
uksort(\$array, function (\$a, \$b) {
\$t1 = strtotime(str_replace(["date_", "_"], ["", "-"], \$a) . '-01');
\$t2 = strtotime(str_replace(["date_", "_"], ["", "-"], \$b) . '-01');
return \$t1 - \$t2;
});
``````

Step 2: Main logic to given condition with inline documentation

``````\$flag   = false;
\$result = [];
foreach (\$array as \$key => \$value) {
if (\$key != 'date_2019_01' && !\$flag) {
continue; // check until 'date_2019_01' wont come
} else {
\$flag   = true; // set the flag and skip above condition
\$curKey = array_search(\$key, array_keys(\$array), true); // get integer index of date_2019_01
if (\$key !== false) { // if key exists
\$slice        = array_slice(\$array, \$curKey - 5, 6, true); // from current index last 5(6-5, 7-5,8-5,....) to 6(including current element)
\$result[\$key] = array_sum(\$slice); // sum of there values
}
}
}
``````

Brief of things I have used to make it clear for understanding of applications of it.

uksort — Sort an array by keys using a user-defined comparison function
array_keys — Return all the keys or a subset of the keys of an array
array_search — Searches the array for a given value and returns the first corresponding key if successful
array_slice — Extract a slice of the array
array_sum — Calculate the sum of values in an array
str_replace — Replace all occurrences of the search string with the replacement string

• that was a very good explanation. Thank You. – S S Apr 19 at 10:56