PHP, Jquery get multi array, combine a row - php

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

Related

Sum values of array with same key and values

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.

Properly getting the sorting order of this array in PHP

I have a 2-dimensional array which the values...
9999999999999999 3201 4584 4821 1628 1218 1786 4738 4897
3122 9999999999999999 1400 1638 1797 2756 3323 5310 5472
4523 1400 9999999999999999 237 3198 4156 4723 6711 6872
4760 1638 237 9999999999999999 3435 4394 4961 6948 7110
1324 1846 3247 3485 9999999999999999 958 1525 3931 4093
932 2854 4273 4510 1002 9999999999999999 567 4873 5034
1499 3422 4840 5078 1569 567 9999999999999999 5440 5602
5061 5359 6760 6998 4019 4959 5526 9999999999999999 161
5233 5531 6931 7169 4190 5130 5697 171 9999999999999999
Here's the same array in code:
array:9 [
0 => array:9 [
0 => 9999999999999999
1 => 3122
2 => 4523
3 => 4760
4 => 1324
5 => 932
6 => 1499
7 => 5061
8 => 5233
]
1 => array:9 [
0 => 3201
1 => 9999999999999999
2 => 1400
3 => 1638
4 => 1846
5 => 2854
6 => 3422
7 => 5359
8 => 5531
]
2 => array:9 [
0 => 4584
1 => 1400
2 => 9999999999999999
3 => 237
4 => 3247
5 => 4273
6 => 4840
7 => 6760
8 => 6931
]
3 => array:9 [
0 => 4821
1 => 1638
2 => 237
3 => 9999999999999999
4 => 3485
5 => 4510
6 => 5078
7 => 6998
8 => 7169
]
4 => array:9 [
0 => 1628
1 => 1797
2 => 3198
3 => 3435
4 => 9999999999999999
5 => 1002
6 => 1569
7 => 4019
8 => 4190
]
5 => array:9 [
0 => 1218
1 => 2756
2 => 4156
3 => 4394
4 => 958
5 => 9999999999999999
6 => 567
7 => 4959
8 => 5130
]
6 => array:9 [
0 => 1786
1 => 3323
2 => 4723
3 => 4961
4 => 1525
5 => 567
6 => 9999999999999999
7 => 5526
8 => 5697
]
7 => array:9 [
0 => 4738
1 => 5310
2 => 6711
3 => 6948
4 => 3931
5 => 4873
6 => 5440
7 => 9999999999999999
8 => 171
]
8 => array:9 [
0 => 4897
1 => 5472
2 => 6872
3 => 7110
4 => 4093
5 => 5034
6 => 5602
7 => 161
8 => 9999999999999999
]
]
What I'm trying to achieve is find the sorting order of this array in terms of closest. Each row contains the distance of a place to another place.
In other words, the array looks something like:
China India USA Japan
China 0 50 4000 2000
India 50 0 4100 2100
USA 4050 4120 2 3000
Japan 2010 1950 2997 0
As you can see, the value to self is 0, sometimes it's a small number like 2-10 (not really sure thou) because Google distance matrix API sometimes returns big values for same origin and destination too which is why I replaced it to 9999999999999999 throughout the diagonal in my original array above.
The goal is to get the sorting in terms of distance. The first entry is the starting point so in the case of the hypothetical array above it would be:
[0 1 3 2] i.e. From China to India, then India to Japan, and Japan to the USA. My goal is to use array_multisort, in the end, to order just the keys with the place names so that it's ordered properly.
The code I came up with isn't working as I hoped for:
$order = [0];
$i = 0;
$nextItemToProcessIndex = 0;
foreach($tempMatrix as $key => $entry) {
$tempMatrix[$key][$key] = PHP_INT_MAX;
}
while(!empty($tempMatrix)) {
$closestItemIndex = array_search(min($tempMatrix[$nextItemToProcessIndex]), $tempMatrix[$nextItemToProcessIndex]);
array_push($order, $closestItemIndex);
$this->pull_item($tempMatrix, $nextItemToProcessIndex);
$nextItemToProcessIndex = $closestItemIndex - 1;
$i++;
}
dd($order);
...
...
public function pull_item(&$array, $offset) {
array_walk($array, function (&$v) use ($offset) {
array_splice($v, $offset, 1);
});
$row = array_splice($array, $offset, 1);
return $row;
}
If altering matrix column labels is ok for you - you can do sorting like that:
$dist = [
"China" => ['China' => 0, 'India' => 50, 'USA' => 4000, 'Japan' => 2000],
"India" => ['China' => 50, 'India' => 0, 'USA' => 4100, 'Japan' => 2100],
"USA " => ['China' => 4050, 'India' => 4120, 'USA' => 2, 'Japan' => 3000],
"Japan" => ['China' => 2010, 'India' => 1950, 'USA' => 2997, 'Japan' => 0]
];
// sort columns by distance
foreach ($dist as $key => $value) {
asort($dist[$key]);
}
// display distances matrix
foreach ($dist as $row_c => $data) {
$row1 = "\t";
$row2 = $row_c . " : ";
foreach ($data as $col_c => $col_dist) {
$row1 .= $col_c . "\t";
$row2 .= $col_dist . "\t";
}
echo "{$row1}\n{$row2}\n\n";
}
Outputs:
China India Japan USA
China : 0 50 2000 4000
India China Japan USA
India : 0 50 2100 4100
USA Japan China India
USA : 2 3000 4050 4120
Japan India China USA
Japan : 0 1950 2010 2997
I was able to figure out a solution to this on my own. Posting here if anyone else comes across the same issue:
$nextItemToProcess = 0;
$order = [0];
foreach(range(0, count($tempMatrix) - 2) as $i) {
if(count(array_diff_key($tempMatrix[$nextItemToProcess], $order)) == 1) {
$order = array_merge($order, array_diff(range(0, count($tempMatrix)-1), $order));
break;
}
$diffArray = array_diff_key($tempMatrix[$nextItemToProcess], array_flip($order));
$closestItemIndex = array_search(min($diffArray), $tempMatrix[$nextItemToProcess]);
array_push($order, $closestItemIndex);
$nextItemToProcess = $closestItemIndex;
}
$ascOrigins = [];
foreach($order as $i) {
array_push($ascOrigins, $arrOrigins[$i]);
}
ascOrigins is the array in ascending order of place distances. I thought I could use php's array_multisort but it wasn't useful since here I'm sorting the keys of arr based on the values of order. (I know an array_flip could have done the trick but this works fine).

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 |
+------+-----------+

Fill multidimensional array from other array

I have a multidimensional array $elements where I need to fill it with values from the array $ratings. The array $ratings is built so the first value will fit into the first slot in elements, the next in the second and so on.
$elements
4 => array:3 [▼
2 => 0
3 => 0
4 => 0
]
5 => array:3 [▼
2 => 0
3 => 0
4 => 0
]
7 => array:3 [▼
2 => 0
3 => 0
4 => 0
]
I now need to fill $elements with 9 specific values from
$ratings
array:9 [▼
0 => 3
1 => 2
2 => 1
3 => 3
4 => 3
5 => 2
6 => 3
7 => 2
8 => 1
9 => 3
]
If I manage to loop through $elements, inserting values from $ratings one by one, I will have solved my problem.
So $elements[4][2] should have the value of 3, $elements[4][3] should have value of 2 etc.
Also you can manipulate these by array_fill using loop.
Try this:
<?php
$elements = [
4=>[2=>0, 3=>0, 4=>0],
5=>[2=>0, 3=>0, 4=>0],
7=>[2=>0, 3=>0, 4=>0],
];
$ratings = [ 0 => 3, 1 => 2, 2 => 1, 3 => 3, 4 => 3, 5 => 2, 6 => 3, 7 => 2, 8 => 1, 9 => 3 ];
$ratingsIndex = 0;
foreach(array_keys($elements) as $ElementsIndex) {
foreach(array_keys($elements[$ElementsIndex]) as $ElementsSubIndex) {
$elements[$ElementsIndex][$ElementsSubIndex] = $ratings[$ratingsIndex++];
}
}
echo "<pre>";
print_r($elements);
echo "</pre>";
?>

Calculate overall and division ranking via arrays

This is a follow-up to Detect future duplicate values while iterating through MySQL results in PHP.
I have an SQL query which produces the results:
team_id division_id wins
-------------------------------
10 2 44
9 2 42
5 1 42
2 1 42
3 1 41
11 2 40
1 1 36
8 2 31
7 2 29
12 2 24
4 1 20
6 1 18
I'm trying to calculate a given team's overall and divisional rankings.
For example, team_id = 1:
Overall: 7
Divisional: 4
For team_id = 3:
Overall: 5
Divisional: 3
For team_id = 9:
Overall: T-2 //must indicate tie
Divisional: 2
As you can see from the linked previous question/answer, I can calculate the Overall rank just fine. The issue comes with calculating the divisional rank as well (including properly handling ties).
I've tried storing the results in a multi-dimensional array like $arr['wins']['division_id']['team_id'], such as...
44 => 2 => 10
42 => 1 => 5
2
2 => 9
41 => 1 => 3
40 => 11 => 2
...
But am stuck as to how to iterate through and get my two respective ranks, as well as detecting ties appropriately for each.
Try something like this:
// Dataset as defined on question
$arr = array(
array('team_id' => 10, 'division_id' => 2, 'wins' => 44),
array('team_id' => 9, 'division_id' => 2, 'wins' => 42),
array('team_id' => 5, 'division_id' => 1, 'wins' => 42),
array('team_id' => 2, 'division_id' => 1, 'wins' => 42),
array('team_id' => 3, 'division_id' => 1, 'wins' => 41),
array('team_id' => 11, 'division_id' => 2, 'wins' => 40),
array('team_id' => 1, 'division_id' => 1, 'wins' => 36),
array('team_id' => 8, 'division_id' => 2, 'wins' => 31),
array('team_id' => 7, 'division_id' => 2, 'wins' => 29),
array('team_id' => 12, 'division_id' => 2, 'wins' => 24),
array('team_id' => 4, 'division_id' => 1, 'wins' => 20),
array('team_id' => 6, 'division_id' => 1, 'wins' => 18));
$divisionTeam = array();
$divisionWins = array();
foreach($arr as $team) {
$divisionTeam[$team['division_id']][] = $team['team_id'];
$divisionWins[$team['division_id']][] = $team['wins'];
}
echo "<pre>";
foreach (array_keys($divisionTeam) as $division_id) {
$rank = 0;
$prevWins = -1;
echo "DIVISION $division_id \n";
foreach ($divisionTeam[$division_id] as $index => $team_id) {
if ($prevWins == $divisionWins[$division_id][$index]) {
echo $team_id . " T - " . $rank . "\n";
}
else {
$rank++;
echo $team_id . " " . $rank . "\n";
}
$prevWins = $divisionWins[$division_id][$index];
}
}
echo "</pre>";

Categories