Sum values of array with same key and values - php

I'm trying to sum a value of an array with the same employee no.
Here's the example of the array I'm trying to sum.
0 => array:10 [▼
"employee_no" => "04052018"
"employee_id" => 317
"company_id" => 4
"name" => ""
"monthly_salary" => 14000.0
"daily_salary" => 537.0
"work_hours" => 8
"sss_deduction" => 0
"pagibig_deduction" => 100
"philhealth_deduction" => 192
and
0 => array:10 [▼
"employee_no" => "04052018"
"employee_id" => 317
"company_id" => 4
"name" => ""
"monthly_salary" => 14000.0
"daily_salary" => 537.0
"work_hours" => 8
"sss_deduction" => 0
"pagibig_deduction" => 100
"philhealth_deduction" => 192
they are duplicates array in which i want to get the sum of work hours only to have this result
0 => array:10 [▼
"employee_no" => "04052018"
"employee_id" => 317
"company_id" => 4
"name" => ""
"monthly_salary" => 14000.0
"daily_salary" => 537.0
"work_hours" => 16
"sss_deduction" => 0
"pagibig_deduction" => 100
"philhealth_deduction" => 192
There are about 24 and more occurrences if this array in my result set in which i want to merge as one summing up the total work hours
Tried this one but getting no luck
foreach ($employee_attendance as $row){
if($row['employee_id'] === $row['employee_id']){
$payroll_data['work_hours'] += $row['total_hours'];
}
$payroll[] = $payroll_data;
}

The best would be to get it sorted out from Eloquent queries itself. However, if you wish, you can also use Collections' methods such as groupBy and each to filter the values based on employee ID and do a sum on them. Finally, have a result variable to store all the results.
Snippet:
$result = [];
$arr = $arr->groupBy('employee_no')->each(function($item,$key) use (&$result){
$sum = $item->sum('work_hours');
$emp_data = $item->first();
$emp_data['work_hours'] = $sum;
$result[] = $emp_data;
});
Full Code:
<?php
$arr = collect([
[
"employee_no" => "04052018",
"employee_id" => 317,
"company_id" => 4,
"name" => "",
"monthly_salary" => 14000.0,
"daily_salary" => 537.0,
"work_hours" => 8,
"sss_deduction" => 0,
"pagibig_deduction" => 100,
"philhealth_deduction" => 192
],
[
"employee_no" => "04052018",
"employee_id" => 317,
"company_id" => 4,
"name" => "",
"monthly_salary" => 14000.0,
"daily_salary" => 537.0,
"work_hours" => 8,
"sss_deduction" => 0,
"pagibig_deduction" => 100,
"philhealth_deduction" => 192
],
[
"employee_no" => "04052019",
"employee_id" => 317,
"company_id" => 4,
"name" => "",
"monthly_salary" => 14000.0,
"daily_salary" => 537.0,
"work_hours" => 80,
"sss_deduction" => 0,
"pagibig_deduction" => 100,
"philhealth_deduction" => 192
]
]);
$result = [];
$arr = $arr->groupBy('employee_no')->each(function($item,$key) use (&$result){
$sum = $item->sum('work_hours');
$emp_data = $item->first();
$emp_data['work_hours'] = $sum;
$result[] = $emp_data;
});
print_r($result);

As what others said, it's better to group and sum those work hours when you retrieve it from the database.
But in case you still want to do it like what you explained above, it can be done like this although it might not be the best way
foreach ($employee_attendance as $row){
// Check if this is the first occurence of the employee number or not
if (!isset ($payroll_data[$row['employee_no']]['work_hours']) ) {
// First occurence will set the total hours to the current loop work hours
$payroll_data[$row['employee_no']]['work_hours'] = $row['work_hours'];
} else {
// Second occurence and so on will sum previous total work hours
$payroll_data[$row['employee_no']]['work_hours'] += $row['work_hours'];
}
}
And the $payroll_data structure will be like this:
[
"04052018" => [
"work_hours" => 16 // Total work hours of this employee number
],
// Repeat for other employee number
]
Hence, it's easier for you to check the employee number with their total working hours as well.

Related

PHP, Jquery get multi array, combine a row

Concept:
Adding Floors and Room counts and Room Numbers in a Hotel and saving it in a db
Front end Design:
Please have a look at this image
Backend what i am getting now:
"floor" => array:3 [▼
0 => "3"
1 => "2"
2 => "1"
]
"room_count" => array:3 [▼
0 => "3"
1 => "3"
2 => "5"
]
"room_number" => array:11 [▼
0 => "101"
1 => "102"
2 => "103"
3 => "201"
4 => "202"
5 => "203"
6 => "101"
7 => "102"
8 => "103"
9 => "104"
10 => "105"
]
The Question is:
How can i loop through to get:
Floor 3 has the room numbers 101, 102, 103
Floor 2 has the room numbers 201, 202, 203
Floor 1 has the room numbers 101, 102, 103, 104, 105
Iterate through each floor, count the number of rooms, and then determine which room numbers are associated with that floor by working through the array of room numbers.
Given the array structure you're working with, the trick is that you'll need to have a loop like this one that can track the $prev_index by incrementing $prev_index by the room count at each floor.
<?php
$array = array(
'floor' => array(
0 => '3',
1 => '2',
2 => '1',
),
'room_count' => array(
0 => '3',
1 => '3',
2 => '5',
),
'room_number' => array(
0 => '101',
1 => '102',
2 => '103',
3 => '201',
4 => '202',
5 => '203',
6 => '101',
7 => '102',
8 => '103',
9 => '104',
10 => '105',
),
);
for ($prev_index = 0, $i = 0; $i < count($array['floor']); ++$i) {
$floor = $array['floor'][$i];
$room_count = $array['room_count'][$i];
$room_numbers = array_slice($array['room_number'], $prev_index, $room_count);
$prev_index = $prev_index + $room_count;
echo 'Floor '.$floor.' has '.$room_count.' rooms, with room numbers '.implode(', ', $room_numbers)."\n";
}
Floor 3 has 3 rooms, with room numbers 101, 102, 103
Floor 2 has 3 rooms, with room numbers 201, 202, 203
Floor 1 has 5 rooms, with room numbers 101, 102, 103, 104, 105

Total for columns in a table

I want to calculate the totals for a series of columns in a table, how do I go about doing this?
Here is a sample of the data I want to sum:
array:1 [
"traders" => array:6 [
"Jim Mayor__targeted_target" => array:2 [
"amounts" => array:13 [
0 => 5
1 => 5
2 => 0
3 => 0
4 => 0
5 => 0
6 => 0
7 => 0
8 => 0
9 => 0
10 => 0
11 => 0
]
"row_name" => "Targeted target"
]
"Jim Mayor__actual_targeted" => array:2 [
"amounts" => array:13 [
0 => 0
1 => 1
2 => 0
3 => 0
4 => 0
5 => 0
6 => 1
7 => 1
8 => 0
9 => 0
10 => 0
11 => 0
]
"row_name" => "Actual targeted"
]
"Bob Martinez__targeted_target" => array:2 [
"amounts" => array:13 [
0 => 1
1 => 0
2 => 0
3 => 0
4 => 0
5 => 0
6 => 0
7 => 0
8 => 0
9 => 0
10 => 0
11 => 0
]
"row_name" => "Targeted target"
]
"Bob Martinez__actual_targeted" => array:2 [
"amounts" => array:13 [
0 => 19
1 => 45
2 => 20
3 => 26
4 => 21
5 => 10
6 => 12
7 => 20
8 => 11
9 => 2
10 => 0
11 => 0
]
"row_name" => "Actual targeted"
]
...
I want to sum together each index, e.g. for Jim Mayor__targeted_target, index 0 added to index 0 of Bob Martinez__targeted_target (this gives the total for January). It needs to work with an unlimited number of traders.
The function that generates the data:
protected function addRow($func, $params, $data, $year, $traderName, $rowName, $type, $image = null, $format = null, $underline = false)
{
$date = Carbon::createFromDate($year, 4, 1);
$total = 0;
$traderName = $traderName . '__' . str_replace(' ', '_', strtolower($rowName));
for ($i = 1; $i < 13; $i++) {
$params[1] = $date->year;
$params[2] = $date->month;
$result = call_user_func_array($func, $params);
$data['traders'][$traderName]['amounts'][] = $result ? $result : 0;
$total += $result;
$date->addMonth();
}
$data['traders'][$traderName]['amounts'][] = $total;
$data['traders'][$traderName]['row_name'] = $rowName;
return $data;
}
Just go over your data and save results in an additional array:
$results = array();
foreach ($traders as $trader) {
foreach ($trader['amounts'] as $i => $amount) {
if (!isset($results[$i])) {
$results[$i] = 0;
}
$results[$i] += $amount;
}
}
The result array will contains the sums of all traders.
Not tested but should work.
Do something like this:
function sumRowsByMonth($traders)
{
$sums = array_fill(0, 12, 0);
foreach($traders as $trader) {
foreach($trader['amounts'] as $monthId => $amount) {
$sums[$monthId] += $amount;
}
}
return $sums;
}
I tested with this:
$arr = array(
'traders' => array(
'Jim Mayor__targeted_target' => array(
'amounts' => array(
0 => 5,
1 => 5,
2 => 0,
3 => 0,
4 => 0,
5 => 0,
6 => 0,
7 => 0,
8 => 0,
9 => 0,
10 => 0,
11 => 0,
)
),
'Bob Martinez__targeted_target' => array(
'amounts' => array(
0 => 19,
1 => 45,
2 => 20,
3 => 26,
4 => 21,
5 => 10,
6 => 12,
7 => 20,
8 => 11,
9 => 2,
10 => 0,
11 => 0,
)
),
),
);
var_dump(sumRowsByMonth($arr['traders']));
Use array_sum() function.
array_sum() returns the sum of values in an array
Also, you said you want to count targeted target and actual targeted separately.
$actual = [];
$targeted = [];
foreach ($traders as $trader) {
$sum = array_sum($trader['anmounts']);
$trader['row_name'] === 'Actual targeted') ? $actual += $sum : $target += $sum;
}
Maybe you'll need to modify this a little bit to tune behavior, but I guess I got the idea.
#imperium2335:
The main problem I keep getting that it is summing all rows, including actual_targeted. actual_targeted needs to be grouped and summed separately to targeted_target.
Then do this:
function sumRowsByMonth($traders)
{
$sums = array();
foreach($traders as $traderName => $trader) {
$type = strstr($traderName, '__');
if( empty($sums[$type]) ) {
$sums[$type] = array_fill(0, 12, 0);
}
foreach($trader['amounts'] as $monthId => $amount) {
$sums[$type][$monthId] += $amount;
}
}
return $sums;
}
Read this:
http://php.net/manual/en/function.strstr.php

Calculate values of deep nested multi dimensional arrays in reverse

I need to calculate reward for employees in my company.
I have this structure (for example):
And in PHP it represents the following array:
<?php
$structure = [
"A" => [
"B" => [
"E" => [
"M" => null
],
"F" => [
"N" => [
"T" => null
],
"O" => null
],
"G" => [
"P" => null,
"Q" => [
"U" => null,
"V" => [
"X" => null,
"Y" => [
"3" => [
"4" => [
"4" => null,
"6" => null,
"7" => [
"8" => null
],
]
]
],
"Z" => null
]
]
],
"H" => null
],
"C" => [
"I" => null,
"J" => [
"R" => null
],
"K" => [
"S" => [
"W" => [
"1" => null,
"2" => null,
]
]
]
],
"D" => [
"L" => null
]
]
];
I need to calculate the reward for each employee. The end subordinates have reward only from their own work. But the seniors who have other subordinates have reward from their own work + works their subordinates.
For example:
Person A has own reward 10.
Person D has own reward 20.
Person L has own reward 15.
In the final,
Person L has final reward 15 (is final).
Person D has final reward 20 + 15 = 35 (D + L).
Person A has final reward 10 + 35 (A + D).
The calculation must be carried out below, however, the network can be arbitrarily deep. Calculating I would like to split into several parts. (For performance reasons)
The spider, which revises the structure to the appropriate format.
Calculate reward for each node.
Send information about each node via email.
I do not know how to proceed across the structure. Or to reorganize the structure to undergo easier. Can you think of anything?
I am grateful for you. Thanks!
#Martin
// EDIT: raw database
| id | parent | name
---------------------
| 1 | null | Martin
| 2 | null | Peter
| 3 | 1 | John
| 4 | 3 | Jack
// EDIT: new data structure:
[
"A" => [
"points" => 20,
"childs" => [
"B" => [
"points" => 10,
"childs" => [
"C" => [
"points" => 50,
"childs" => null
]
]
],
"D" => [
"points" => 30,
"childs" => [
"4" => [
"points" => 40,
"childs" => null
]
]
]
]
]
]
This can be done by traversing through the structure recursively from the inside-out, and stores the rewards for each employee it can find in a flattened 2D array.
It is dependent on each leaf of the structure having a starting value, as it needs a base value to calculate back up the tree on.
Using RecursiveIteratorIterator with the CHILD_FIRST flag allows you to loop through the array 'backwards' which is what we want in this case as that is where the starting rewards are. As we go through the tree, we obtain the subordinates rewards, add it to the current employee, and continue .. so by the time we get back to the top of the structure, we have calculated all employees.
Storing the result in a flattened array is then much easier to use and manipulate further along your logic.
Assumed starting structure:
// Each leaf has a value (random for example sake)
$structure = [
"A" => [
"B" => [
"E" => [
"M" => 10
],
"F" => [
"N" => [
"T" => 15
],
"O" => 5
],
"G" => [
"P" => 40,
"Q" => [
"U" => 30,
"V" => [
"X" => 35,
"Y" => [
"3" => [
"4" => [
"5" => 5,
"6" => 10,
"7" => [
"8" => 20
],
]
]
],
"Z" => 30
]
]
],
"H" => 15
],
"C" => [
"I" => 25,
"J" => [
"R" => 25
],
"K" => [
"S" => [
"W" => [
"1" => 40,
"2" => 50,
]
]
]
],
"D" => [
"L" => 15
]
]
];
Calculation:
// Iterate through the structure from the outside-in (child/leaves first)
$data = new RecursiveArrayIterator($structure);
$dataIt = new RecursiveIteratorIterator($data, RecursiveIteratorIterator::CHILD_FIRST);
$rewards = [];
foreach ($dataIt as $value) {
$subKeys = [];
$rewards[$dataIt->key()] ?? $rewards[$dataIt->key()] = 0; // Suppress any undefined index errors
if (is_array($value)) {
$subKeys = array_keys($value);
// traverse through all branches to obtain the existing reward values for subordinates
array_walk_recursive($value, function($reward, $person) use (&$subKeys) {
$subKeys[] = $person;
});
$subKeys = array_unique($subKeys);
foreach ($subKeys as $employee) {
$rewards[$dataIt->key()] += $rewards[$employee];
}
} else {
$rewards[$dataIt->key()] += $value;
}
}
print_r($rewards);
Return/final array:
Array
(
[M] => 10
[E] => 10
[T] => 15
[N] => 15
[O] => 5
[F] => 35
[P] => 40
[U] => 30
[X] => 35
[4] => 60
[6] => 10
[8] => 20
[7] => 20
[3] => 90
[Y] => 180
[Z] => 30
[V] => 335
[Q] => 520
[G] => 745
[H] => 15
[B] => 1060
[I] => 25
[R] => 25
[J] => 25
[1] => 40
[2] => 50
[W] => 90
[S] => 180
[K] => 270
[C] => 435
[L] => 15
[D] => 15
[A] => 1935
)
To get the number of employees under each node, you can do that easily in one line using count:
$employeesPersonA = count($structure['A'], COUNT_RECURSIVE); // 33
$employeesPersonC = count($structure['A']['C'], COUNT_RECURSIVE); // 8
$employeesPersonK = count($structure['A']['C']['K'], COUNT_RECURSIVE); // 4
EDIT:
For your database structure, you cannot get a multi dimensional result set out of the database so your only option there is to go through the result set and build your structure in PHP from that.
Here's one example, simplified to consider only nodes, 'A','B','C',D', & 'L'...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(user CHAR(1) NOT NULL PRIMARY KEY
,lft INT NOT NULL
,rgt INT NOT NULL
);
INSERT INTO my_table VALUES
('A',1,10),
('B',2,3),
('C',4,5),
('D',6,9),
('L',7,8);
SELECT y.user
, GROUP_CONCAT(x.user ORDER BY x.lft) nodes
FROM my_table x
JOIN my_table y
ON x.lft BETWEEN y.lft AND y.rgt
GROUP
BY y.user
ORDER
BY y.lft;
+------+-----------+
| user | nodes |
+------+-----------+
| A | A,B,C,D,L |
| B | B |
| C | C |
| D | D,L |
| L | L |
+------+-----------+

PHP- Sorting multidimensional array into another by range of numbers

I have a multidimensional array that I get from DB. Array has a number of views by each hour that is logged in the DB as a view, and it looks like this:
array:11 [▼
0 => array:2 [▼
"hour" => 0
"views" => 1
]
1 => array:2 [▼
"hour" => 1
"views" => 1
]
2 => array:2 [▼
"hour" => 4
"views" => 1
]
...and so on
]
I need to make a new array that will contain number of views for range of 2 hours. So for example from the array shown above I would like to get an array with, number of views for time between 0-2, that would 2, and for 2-4, would be 0 in this case, and so on.
You can do it in Mysql query:
select floor(hour/2) range, sum(views) sum
from thetable
group by range
You can just use a foreach to create a new array.
<?php
$your_array = [0 => [
"hour" => 0,
"views" => 4
],
1 => [
"hour" => 1,
"views" => 12
],
2 => [
"hour" => 4,
"views" => 1
],
3 => [
"hour" => 2,
"views" => 9
],
4 => [
"hour" => 21,
"views" => 19
]
];
foreach ($your_array as $value){
for($i=0;$i<=22;$i=$i+2){
$j=$i+2;
if($value['hour']>=$i && $value['hour']<$j){
isset($result[$i.'-'.$j])?$result[$i.'-'.$j]+=$value['views']:$result[$i.'-'.$j]=$value['views'];
}
}
}
print_r($result);
Try below code.
$arr = [0 => [
"hour" => 0,
"views" => 1
],
1 => [
"hour" => 1,
"views" => 1
],
2 => [
"hour" => 4,
"views" => 1
]];
foreach($arr as $row)
{
if($row['hour'] >= 0 && $row['hour'] <= 2)
{
$newArr['0-2'] = isset($newArr['0-2']) ? ($newArr['0-2'] + 1) : 1;
}
if($row['hour'] > 2 && $row['hour'] < 4)
{
$newArr['2-4'] = isset($newArr['2-4']) ? ($newArr['2-4'] + 1) : 1;
}
}
print_r($newArr);
Output
Array
(
[0-2] => 2
)

Concatenate strings from 2 array based on key

so i have a bit difficulty in combining arrays in php. So let say i have these 2 array
array:4 [▼
20 => "University"
21 => "Polic Station"
22 => "Ambulance"
1 => "Zoo"
]
array:4 [▼
20 => "abc"
21 => "def"
22 => "ghi"
1 => "jkl"
]
How do i actually combine this to this
array:4 [▼
20 => "abc University"
21 => "def Polic Station"
22 => "ghi Ambulance"
1 => "jkl Zoo"
]
Here's the result:
$arr = array(
20=>'University',
21=>'Polic Station',
22=>'Ambulance',
1=>'Zoo');
$arr2= array(
20=>'abc',
21=>'def',
22=>'ghi',
1=>'jkl');
$arr_out = array();
foreach($arr as $key=>$el) {
$arr_out[$key] = $arr2[$key] ." ".$el;
}
var_dump($arr_out);
Obviously, you'll need to keep in mind to check whether the key exists in the second array so you do not get an error when accessing the value.

Categories