Add up the array values based on the same key (PHP) - php

I found a case where I had to add values based on the same week.
[{"week":"30","nilai":"230"},{"week":"30","nilai":"66"},{"week":"29","nilai":"72"},{"week":"29","nilai":"225"},{"week":"28","nilai":"213"},{"week":"28","nilai":"72"},{"week":"27","nilai":"191"},{"week":"27","nilai":"60"},{"week":"26","nilai":"176"},{"week":"26","nilai":"65"},{"week":"25","nilai":"167"},{"week":"25","nilai":"57"},{"week":"24","nilai":"209"},{"week":"24","nilai":"62"},{"week":"23","nilai":"180"},{"week":"23","nilai":"88"},{"week":"22","nilai":"178"},{"week":"22","nilai":"72"},{"week":"21","nilai":"164"},{"week":"21","nilai":"42"},{"week":"20","nilai":"193"},{"week":"20","nilai":"50"},{"week":"19","nilai":"186"},{"week":"19","nilai":"56"}]
the results I expect among others are like this
week => 30,
nilai=> 296

<?php
$input = '[{"week":"30","nilai":"230"},{"week":"30","nilai":"66"},{"week":"29","nilai":"72"},{"week":"29","nilai":"225"},{"week":"28","nilai":"213"},{"week":"28","nilai":"72"},{"week":"27","nilai":"191"},{"week":"27","nilai":"60"},{"week":"26","nilai":"176"},{"week":"26","nilai":"65"},{"week":"25","nilai":"167"},{"week":"25","nilai":"57"},{"week":"24","nilai":"209"},{"week":"24","nilai":"62"},{"week":"23","nilai":"180"},{"week":"23","nilai":"88"},{"week":"22","nilai":"178"},{"week":"22","nilai":"72"},{"week":"21","nilai":"164"},{"week":"21","nilai":"42"},{"week":"20","nilai":"193"},{"week":"20","nilai":"50"},{"week":"19","nilai":"186"},{"week":"19","nilai":"56"}]';
$input = json_decode($input, true);
$outArr = [];
foreach ($input as $arr) {
$week = $arr['week'];
if (key_exists($week, $outArr)) {
$outArr[$week] += $arr['nilai'];
} else {
$outArr[$week] = $arr['nilai'];
}
}
//optional sort - you may remove it
ksort($outArr);
$outArr2 = [];
foreach($outArr as $week => $nilai) {
$outArr2[] = ['week' => $week, 'nilai' => $nilai];
}
var_export($outArr2);
gives result:
array (
0 =>
array (
'week' => 19,
'nilai' => 242,
),
1 =>
array (
'week' => 20,
'nilai' => 243,
),
2 =>
array (
'week' => 21,
'nilai' => 206,
),
3 =>
array (
'week' => 22,
'nilai' => 250,
),
4 =>
array (
'week' => 23,
'nilai' => 268,
),
5 =>
array (
'week' => 24,
'nilai' => 271,
),
6 =>
array (
'week' => 25,
'nilai' => 224,
),
7 =>
array (
'week' => 26,
'nilai' => 241,
),
8 =>
array (
'week' => 27,
'nilai' => 251,
),
9 =>
array (
'week' => 28,
'nilai' => 285,
),
10 =>
array (
'week' => 29,
'nilai' => 297,
),
11 =>
array (
'week' => 30,
'nilai' => 296,
),
)

<?php
$input = '[{"week":"30","nilai":"230"},{"week":"30","nilai":"66"},{"week":"29","nilai":"72"},{"week":"29","nilai":"225"},{"week":"28","nilai":"213"},{"week":"28","nilai":"72"},{"week":"27","nilai":"191"},{"week":"27","nilai":"60"},{"week":"26","nilai":"176"},{"week":"26","nilai":"65"},{"week":"25","nilai":"167"},{"week":"25","nilai":"57"},{"week":"24","nilai":"209"},{"week":"24","nilai":"62"},{"week":"23","nilai":"180"},{"week":"23","nilai":"88"},{"week":"22","nilai":"178"},{"week":"22","nilai":"72"},{"week":"21","nilai":"164"},{"week":"21","nilai":"42"},{"week":"20","nilai":"193"},{"week":"20","nilai":"50"},{"week":"19","nilai":"186"},{"week":"19","nilai":"56"}]';
$input = json_decode($input, true);
$outArr = [];
foreach ($input as $arr) {
$week = $arr['week'];
if (key_exists($week, $outArr)) {
$outArr[$week]['week'] += $arr['nilai'];
} else {
$outArr[$week]['nilai'] = $arr['nilai'];
}
}
print_r($outArr);
?>

You can do that in a single loop using array_reduce.
This solution performs a true single pass without performing any additional searches in the array. I haven't benchmarked it, but I assume it is more performant.
<?php
$values = json_decode('[{"week":"30","nilai":"230"},{"week":"30","nilai":"66"},{"week":"29","nilai":"72"},{"week":"29","nilai":"225"},{"week":"28","nilai":"213"},{"week":"28","nilai":"72"},{"week":"27","nilai":"191"},{"week":"27","nilai":"60"},{"week":"26","nilai":"176"},{"week":"26","nilai":"65"},{"week":"25","nilai":"167"},{"week":"25","nilai":"57"},{"week":"24","nilai":"209"},{"week":"24","nilai":"62"},{"week":"23","nilai":"180"},{"week":"23","nilai":"88"},{"week":"22","nilai":"178"},{"week":"22","nilai":"72"},{"week":"21","nilai":"164"},{"week":"21","nilai":"42"},{"week":"20","nilai":"193"},{"week":"20","nilai":"50"},{"week":"19","nilai":"186"},{"week":"19","nilai":"56"}]');
print_r($values);
$result = array_reduce($values, function ($carry, $item) {
$carry[$item->week] = (object) [
'week' => $item->week,
'nilai' => ($carry[$item->week]->nilai ?? 0) + $item->nilai,
];
return $carry;
}, []);
print "RESULT ... \n";
print_r($result);
Running on Repl.it at https://repl.it/repls/NauticalDamagedBytecode
This solution gives you an array that is keyed by the week number so that you can directly access them without further looping inside the array to retrieve them.
If you do not want that and if you want the array to me indexed like 0, 1, 2, 3, ... them do $result = array_values(array_reduce( ... )) or $result = array_values($result)

Related

How to subtract all column values in multi-dimensional array in Php?

How can I subtract all the columns values? My array is like
Array
(
[0] => Array
(
[id] => 1
[web_traffic] => 442
[form_users] => 131
[date] => 20181004
)
[1] => Array
(
[id] => 2
[web_traffic] => 102
[form_users] => 15
[date] => 20181003
)
[2] => Array
(
[id] => 3
[web_traffic] => 387
[form_users] => 97
[date] => 20181002
)
)
I need to subtract the each column(except date & id) and get the result based on date(Ascending order). For example 20181004 means 4th October 2018. My output should like the below
Array
(
[web_traffic] => -152
[form_users] => -49
)
My code took reference from How to sum all column values in multi-dimensional array?
foreach ($data as $value) {
unset($value[ 'id' ]);
$time = date('Ymd', strtotime($value[ 'date' ]));
if (in_array($time, $dates)) {
$value[ 'date' ] = $time;
foreach ($value as $key => $secondValue) {
if ( !isset($output[ $key ])) {
$output[ $key ] = 0;
}
$output[ $key ] -= $secondValue;
}
}
}
Use PHP array_reduce() and array_column() like this:
$initial_array = array(array('id' => 1,
'web_traffic' => 442,
'form_users' => 131,
'date' => 20181004),
array('id' => 2,
'web_traffic' => 102,
'form_users' => 15,
'date' => 20181003),
array('id' => 3,
'web_traffic' => 387,
'form_users' => 97,
'date' => 20181002));
function sum($carry, $item)
{
$carry -= $item;
return $carry;
}
$web_traffic = array_column($initial_array, "web_traffic");
$form_users = array_column($initial_array, "form_users");
$date = array_column($initial_array, "date");
array_multisort($date, SORT_ASC, $form_users, SORT_DESC, $initial_array);
$result_array = Array(
"web_traffic" => array_reduce(array_column($initial_array, "web_traffic"), "sum",2*$initial_array[0]['web_traffic']),
"form_users" => array_reduce(array_column($initial_array, "form_users"), "sum",2*$initial_array[0]['form_users'])
);
print_r($result_array);
I would first sort the array using usort() in example.
Sorting first, because that can be tricky to substract in 1 loop the oldest datas to the newers one.
Separating intentions provide a cleaner code, easier to maintain.
The dates don't need to be converted into a date. The string is well formatted and can be used as is in a comparison and a sort. "20170101" < "20180101", "20180101" < "20181001" and "20181002" < "20181004"
When done, I'll save the first values as initial values to be used in substract.
Then, loop the sorted array and substract the 'web_traffic' and 'form_users' to the initial values.
$datas = array(array('id' => 1,
'web_traffic' => 442,
'form_users' => 131,
'date' => 20181004),
array('id' => 2,
'web_traffic' => 102,
'form_users' => 15,
'date' => 20181003),
array('id' => 3,
'web_traffic' => 387,
'form_users' => 97,
'date' => 20181002));
//If needed, you can backup the original array, because usort() will modify it.
$backUpDatas = $datas;
//Sort
usort($datas, function ($arr1, $arr2)
{
if (isset($arr1['date']) && isset($arr2['date']))
{
if ($arr1['date'] == $arr2['date'])
return (0);
return (($arr1['id'] > $arr2['id']) ? (-1) : (1));
}
});
//Initial values
$finalValues['web_traffic'] = $datas[0]['web_traffic'];
$finalValues['form_users'] = $datas[0]['form_users'];
//Substract
foreach ($datas as $key => $value)
{
if ($key > 0)
{
if (isset($value['web_traffic']))
$finalValues['web_traffic'] -= $value['web_traffic'];
if (isset($value['form_users']))
$finalValues['form_users'] -= $value['form_users'];
}
}
var_dump($finalValues);
Output :
array (size=2)
'web_traffic' => int -157
'form_users' => int -49

php array sum key where value is same

I have an array that contains a sub-array. I want to sum the values where the key is the same and to make it in one list.
Here is my array:
$array = array( array(x1=> 1, x2 => 3, y5 => 9),
array(x1=> 3, x4 => 1, y5 => 1),
array(x1=> 1, x8 => 5, a5 => 2),
array(x1=> 2, x10 => 3)
);
And I want to have an array like :
$newarray = array(x1=>7 , x2 => 3, x4=>1, x8=>5, x10=> 3, y5=>9, y5=>1, a5=>2));
some try:
foreach($array as $key => $values)
{
foreach($values as $n_k => $n_v)
{
$newarray [$n_k] += $n_v;
}
}
The problem is you are adding a value even if it is not defined.
You can check if not set by and init the value to 0
if ( !isset($newarray[$n_k]) ) $newarray[$n_k] = 0;
Here is the complete code:
$array = array( array('x1'=> 1, 'x2' => 3, 'y5' => 9), array('x1'=> 3, 'x4' => 1, 'y5' => 1), array('x1'=> 1, 'x8' => 5, 'a5' => 2), array('x1'=> 2, 'x10' => 3, 'b5' => 5));
$newarray = array();
foreach($array as $key => $values){
foreach($values as $n_k => $n_v) {
if ( !isset($newarray[$n_k]) ) $newarray[$n_k] = 0;
$newarray[$n_k] += $n_v;
}
}
This will result to:
Array
(
[x1] => 7
[x2] => 3
[y5] => 10
[x4] => 1
[x8] => 5
[a5] => 2
[x10] => 3
[b5] => 5
)
You can first get all the keys from the array and use that in a array_column and array_sum to get your desired output.
This will probably have more benefit if the array is larger.
$array = array( array("x1" => 1, "x2" => 3, "y5" => 9),
array("x1" => 3, "x4" => 1, "y5" => 1),
array("x1" => 1, "x8" => 5, "a5" => 2),
array("x1" => 2, "x10" => 3, "b5" => 5)
);
$keys = [];
// get all keys used in $array
foreach($array as $subarr){
$keys = array_merge($keys, array_keys($subarr));
}
// $keys is now:
// array (0 => 'x1', 1 => 'x2', 2 => 'y5', 3 => 'x1', 4 => 'x4', 5 => 'y5', 6 => 'x1', 7 => 'x8', 8 => 'a5', 9 => 'x1', 10 => 'x10', 11 => 'b5')
// loop only unique keys and sum the values
foreach(array_unique($keys) as $item){
$res[$item] = array_sum(array_column($array, $item));
}
var_dump($res);
https://3v4l.org/WaqlG
That's not my question, but i've found this that can help you:
https://stackoverflow.com/a/14196064/9721446
You have to create a new array, and then for each equal keyid, you're going to add the value. Somethinkg like that i think it works.
if doesn't help you, take a look at this post, that's not mine too!!!!
Associative array, sum values of the same key
<?php
$input = array( array(x1=> 1, x2 => 3, y5 => 9),
array(x1=> 3, x4 => 1, y5 => 1),
array(x1=> 1, x8 => 5, a5 => 2),
array(x1=> 2, x10 => 3)
);
$final = array();
array_walk_recursive($input, function($item, $key) use (&$final){
$final[$key] = isset($final[$key]) ? $item + $final[$key] : $item;
});
print_r($final);
?>

Merge Array Issue

I have several arrays that all have this structure:
array (
526744 =>
array (
'completed' => 13,
'total' => 24,
'topics' =>
array (
),
'lessons' =>
array (
526745 => 1,
526747 => 1,
526749 => 1,
526751 => 0,
526757 => 0,
526759 => 0,
526761 => 1,
526763 => 0,
526765 => 0,
526767 => 1,
),
'last_id' => 526793,
),
526818 =>
array (
'completed' => 0,
'total' => 22,
'topics' =>
array (
),
'lessons' =>
array (
526819 => 0,
526821 => 1,
526823 => 1,
526845 => 0,
526847 => 1,
526849 => 1,
526859 => 1,
526861 => 1,
),
'last_id' => 526861,
),
)
The number in the outer-most element of the array is a course id. The list of numbers in the inner-most array elements are lesson ids.
I want to merge all of the arrays that contain this structure together. But only ones with the course id of 526744.
If I do something like this:
foreach($results2 as $result2) {
$new_array = unserialize($result2->course_progress);
$final_array = array_merge($final_array, $new_array);
$backup_array = $new_array;
}
This works fine, but it merges the entire arrays, including all courses.
However if I specify the course_id like this:
foreach($results2 as $result2) {
$new_array = unserialize($result2->course_progress);
$newarray = $new_array[526744];
$final_array = array_merge($final_array, $new_array);
$backup_array = $new_array;
}
It no longer merges at all and just lists out the last array for that 1 single course specified.
Any ideas on what is causing this and how to fix it?
Thanks
I have check your code and found the issue, you have used $new_array[526744] which is wrong. it should be array($new_array[526744])
Check this code:
foreach($results2 as $result2) {
$new_array = unserialize($result2->course_progress);
$newarray = array($new_array[526744]);
$final_array = array_merge($final_array, $new_array);
$backup_array = $new_array;
}

need soting multi dimensional array based on another array displaying order

I need sorting array based another array sort value.
Actual array : array(name=>'JK',age=>'20',place=>'India',year=>array(marks1=>array(sub1=>50,sub3=>70,sub7=>65,sub5=>75,sub4=>35), marks2=>array(sub8=>50,sub10=>70,sub12=>75,sub9=>35,sub11=>65))
sorting order array : array(name=>1,year=>2,age=>3,place=>4,sub1=>5,sub3=>6,sub4=>7,sub5=>8,sub7=>9,sub8=>10,sub9=>11,sub10=>12,sub11=>13,sub12=>14)
expected result array:
array(
name=>'JK',
year=>array(
marks1=>array(
sub1=>50,
sub3=>70,
sub4=>35,
sub5=>75
sub7=>65
),
marks2=>array(
sub8=>50,
sub9=>35,
sub10=>70,
sub11=>65,
sub12=>75
),
age=>'20',
place=>'India'
)
I hope this will help :)
$array1 = array(name=>'JK',age=>'20',place=>'India',year=>array(marks1=>array(sub1=>50,sub3=>70,sub7=>65,sub5=>75,sub4=>35), marks2=>array(sub8=>50,sub10=>70,sub12=>75,sub9=>35,sub11=>65));
$array2 = array(name=>1,year=>2,age=>3,place=>4,sub1=>5,sub3=>6,sub4=>7,sub5=>8,sub7=>9,sub8=>10,sub9=>11,sub10=>12,sub11=>13,sub12=>14);
//final array
$final_array = array();
//for each value in sorting array
foreach ($array2 as $key => $value)
{
//store result in final array
$final_array[$value] = $array1[$key];
}
//display array for check result
var_dump($final_array);
I am not exactly sure what is being asked. However, I will take a shot. I think the function you are looking for is uksort.
<?php
$array1 = array(name=>'JK',age=>'20',place=>'India',year=>array(marks1=>array(sub1=>50,sub3=>70,sub7=>65,sub5=>75,sub4=>35), marks2=>array(sub8=>50,sub10=>70,sub12=>75,sub9=>35,sub11=>65)));
function sorter($a,$b)
{
$array2 = array(name=>1,year=>2,age=>3,place=>4,sub1=>5,sub3=>6,sub4=>7,sub5=>8,sub7=>9,sub8=>10,sub9=>11,sub10=>12,sub11=>13,sub12=>14);
return $array2[$a] > $array2[$b];
}
uksort($array1, "sorter");
var_dump($array1);
?>
Here is an example of it running on codepad. You will probably have to work out a bit more since the subs are not sorted. But, possibly is_array can help you out.
$arr1 = array(
'name' => 'JK',
'age' => 20,
'place' => 'India',
'year' =>
array(
'marks1' =>
array('sub1' => 50,
'sub3' => 70,
'sub7' => 65,
'sub5' => 75,
'sub4' => 35),
'marks2' =>
array('sub8' => 50,
'sub10' => 70,
'sub12' => 75,
'sub9' => 35,
'sub11' => 65)));
$arr2 = array('name' => 1, 'year' => 2, 'age' => 3, 'place' => 4, 'sub1' => 5, 'sub3' => 6, 'sub4' => 7, 'sub5' => 8, 'sub7' => 9, 'sub8' => 10, 'sub9' => 11, 'sub10' => 12, 'sub11' => 13, 'sub12' => 14);
foreach ($arr1['year'] as $key => &$value){
uksort($value, function ($a, $b) use($arr2){
return $arr2[$a] - $arr2[$b];
});
}
uksort($arr1, function ($a, $b) use($arr2){
return $arr2[$a] - $arr2[$b];
});
print_r($arr1);
Output:
Array
(
[name] => JK
[year] => Array
(
[marks1] => Array
(
[sub1] => 50
[sub3] => 70
[sub4] => 35
[sub5] => 75
[sub7] => 65
)
[marks2] => Array
(
[sub8] => 50
[sub9] => 35
[sub10] => 70
[sub11] => 65
[sub12] => 75
)
)
[age] => 20
[place] => India
)

Counting values within multidimensional arrays?

I have a large array where I basically need to count the number of uniques:
example array
The end result I am looking for something like
$result = array(
'A3D5' => array('P2' => 1, 'P3' => 1, 'P4' => 1, 'total' => 3),
'AE5S' => array('P4' => 1, 'total' => 1)
);
I've tried foreaching through but can't seem to figure out how to sort them into another key, something like $zone = "P{$array['zone']}"; $result[$zone][$prestige]++ or seems to kind of not work or just error.
$array = array(
"denizen" => array
(
"prestige" => 2,
"zone" => "A3D5",
"scope_frag" => 765
),
"생각" => array
(
"prestige" => 4,
"zone" => "A3D5",
"scope_frag" => 135
),
"Ryans" => array
(
"prestige" => 3,
"zone" => "A3D5",
"scope_frag" => 78
),
"지적인" => array
(
"prestige" => 2,
"zone" => "AE5S",
"scope_frag" => 481
)
);
foreach ($array as $group) {
$zones[$group["zone"]][] = $group["prestige"];
}
foreach ($zones as $name => $zone) {
$total = count($zone);
foreach ($zone as $prestige) {
$result[$name]["P".$prestige] += 1;
}
ksort($result[$name]);
$result[$name]["total"] = $total;
}
echo "<pre>";
print_r($result);
echo "</pre>";

Categories