php loop array to get total - php

I am having some difficulty looping through an array and calculating fields. Here is the array $iroom:
Array
(
[num_rooms] => 2
[adults] => Array
(
[0] => 2
[1] => 2
)
[prices] => Array
(
[0] => 44.5
[1] => 44.5
)
[roomTotalPrice] => Array
(
[0] => 89
[1] => 89
)
[price] => 178
)
I want to (adults*prices)+(adults*$asup)+(chidern*$csup)+$ssup and pu the answer into the roomTotalPrice. So far the outer forloop sets the roomTotalPrice price but I cannot get the inner loops to calculate the price. The $sup are extra supplement prices.
The code I got so far:
foreach($iroom['roomTotalPrice'] as &$irt){
foreach($iroom['adults'] as $ira){
}
$irt = ;
}

CODE WRAPPED IN FUNCTION, TO HANDLE NEW ARRAY FORMAT
/*
Note that this function may not be 100% correct. I notice you have removed
the 'supp' key from the array, and that your current spec doesn't do anything
with the 'price' key. I suspect you may want the line
+ ((isset($array['supp'])) ? $array['supp'] : 0);
to read
+ ((isset($array['price'])) ? $array['price'] : 0);
*/
function calculateTotalPrices ($array, $asup = 10, $csup = 10) {
if (!is_array($array) || !isset($array['num_rooms']) || !$array['num_rooms']) return FALSE; // make sure data is valid
for ($i = 0; $i < $array['num_rooms']; $i++) { // Loop num_rooms times
$array['roomTotalPrice'][$i] =
((isset($array['adults'][$i],$array['prices'][$i])) ? ($array['adults'][$i] * $array['prices'][$i]) + ($array['adults'][$i] * $asup) : 0) // Calculate price for adults
+ ((isset($array['childern'][$i])) ? ($array['childern'][$i] * $csup) : 0) // Calculate price for children
+ ((isset($array['supp'])) ? $array['supp'] : 0); // Add the supplement
}
// Get a total price for adults + children + supplements for all rooms
$array['grandTotal'] = array_sum($array['roomTotalPrice']);
return $array;
}
$iroom = array (
'num_rooms' => 2,
'adults' => array (
0 => 2,
1 => 3
),
'childern' => array (
0 => 1,
1 => 2
),
'prices' => array (
0 => 44.5,
1 => 44.5
),
'price' => 178,
);
print_r(calculateTotalPrices($iroom));
/* With the above array, outputs
Array
(
[num_rooms] => 2
[adults] => Array
(
[0] => 2
[1] => 3
)
[childern] => Array
(
[0] => 1
[1] => 2
)
[prices] => Array
(
[0] => 44.5
[1] => 44.5
)
[price] => 178
[roomTotalPrice] => Array
(
[0] => 119
[1] => 183.5
)
[grandTotal] => 302.5
)
*/
print_r(calculateTotalPrices($iroom,20,25));
/* With your sample array, outputs
Array
(
[num_rooms] => 2
[adults] => Array
(
[0] => 2
[1] => 3
)
[childern] => Array
(
[0] => 1
[1] => 2
)
[prices] => Array
(
[0] => 44.5
[1] => 44.5
)
[price] => 178
[roomTotalPrice] => Array
(
[0] => 154
[1] => 243.5
)
[grandTotal] => 397.5
)
*/
CODE UPDATED WITH ADDITIONAL CHECKS
foreach ($iroom as $k1 => $v1) { // Loop outer array
if (is_array($v1)) { // Make sure element is an array
foreach ($v1 as $k2 => $v2) { // Loop inner array
if (is_array($v2)) { // Make sure element is an array
for ($i = 0; $i < $v2['num_rooms']; $i++) { // Loop num_rooms times
$iroom[$k1][$k2]['roomTotalPrice'][$i] =
((isset($v2['adults'][$i],$v2['prices'][$i])) ? ($v2['adults'][$i] * $v2['prices'][$i]) + ($v2['adults'][$i] * $asup) : 0) // Calculate price for adults
+ ((isset($v2['childern'][$i])) ? ($v2['childern'][$i] * $csup) : 0) // Calculate price for children
+ $v2['supp']; // Add the supplement
}
// Get a total price for adults + children + supplements for all rooms
$iroom[$k1][$k2]['grandTotal'] = array_sum($iroom[$k1][$k2]['roomTotalPrice']);
}
}
}
}
print_r($iroom);
EDIT
Using the exact code above, feeding in the array above, and setting $asup = $csup = 10; at the top, I get no errors, and this output:
Array
(
[10] => Array
(
[12] => Array
(
[num_rooms] => 2
[adults] => Array
(
[0] => 2
[1] => 3
)
[childern] => Array
(
[0] => 1
[1] => 2
)
[prices] => Array
(
[0] => 44.5
[1] => 44.5
)
[price] => 178
[supp] => 0
[roomTotalPrice] => Array
(
[0] => 119
[1] => 183.5
)
[grandTotal] => 302.5
)
)
)
Note that the first result comes out at 119, not 129 as you state in the comment above - this is because in your example array, supp is 0 and not 10, as you have used in your calculation.
I have also tested with more complex arrays (with more elements at the first and second levels) and it works fine.
I'm guessing if you are getting "invalid argument supplied for foreach" errors it's because in your actual array, you highest level has some non-array memebers. This can easily be overcome by changing
foreach ($v1 as $k2 => $v2) {
to
if (is_array($v1)) foreach ($v1 as $k2 => $v2) {

Related

Sync array values across all related array keys

I have a PHP array with the following data
Array
(
[3] => Array
(
[0] => 4095
[2] => 651
)
[4095] => Array
(
[0] => 3
)
[651] => Array
(
[0] => 4432
)
[4432] => Array
(
[0] => 651
)
[92] => Array
(
[0] => 45
)
)
The above array has keys as student_id and the values are also student_id creating a circular relation. What I am trying to achieve is all the student_id has the same set of student_id values. Basically if student_id 3 is related to 4095, 4432 & 651, then, in turn, each of these values has to have 3 among them including other student_id from 3. The below output demonstrates what I am trying to achieve.
Array
(
[3] => Array
(
[0] => 4095
[1] => 4432
[2] => 651
)
[4095] => Array
(
[0] => 3
[1] => 4432
[2] => 651
)
[651] => Array
(
[0] => 3
[1] => 4432
[2] => 4095
)
[4432] => Array
(
[0] => 3
[1] => 4095
[2] => 651
)
[92] => Array
(
[0] => 45
)
[45] => Array
(
[0] => 92
)
)
Explanation of output
The array keys 3, 4095, 651 & 4432 are related to each other either directly or via a common relation (indirect), so will have common set of values (siblings). The key 92 in input array has a value (sibling) of 45, so in a resultant array, a new key 45 will be added to array with the inverse relation as well.
What I have tried so far
I have tried to do it with this code
$syncedSiblings = [];
foreach ($studentsWithSiblings as $sid => $siblings) {
$all = map_assoc(array_merge([$sid], array_keys($siblings)));
foreach ($all as $studentId) {
if (isset($syncedSiblings[$studentId])) {
$old = $syncedSiblings[$studentId];
$syncedSiblings[$studentId] = array_unique(array_merge($old, array_except($all, $studentId)));
} else {
$syncedSiblings[$studentId] = array_unique(array_except($all, $studentId));
}
}
}
Where $studentsWithSiblings has the above array & array_except returns array without the passed values as second argument.
This is the output I am getting right now
Array
(
[3] => Array
(
[0] => 4095
[1] => 651
)
[4095] => Array
(
[0] => 3
[1] => 651
)
[651] => Array
(
[0] => 3
[1] => 4095
[2] => 4432
)
[4432] => Array
(
[0] => 651
)
[92] => Array
(
[0] => 45
)
)
Any help with this will be highly appreciated.
If I've understood you correctly, then this possible to achieve with recursion:
function getChildren($ind_ar, $prev_ar, $data, $rem){
$tmp = [];
$mark = 0;
foreach($ind_ar as $ind){
foreach($data[$ind] as $new_val){
if(!in_array($new_val,$prev_ar) && $new_val != $ind && $new_val != $rem){
$mark = 1;
$tmp[] = $new_val;
}
foreach($data[$new_val] as $new){
if(!in_array($new,$prev_ar) && $new != $ind && $new != $rem){
$mark = 1;
$tmp[] = $new;
}
}
}
}
$res_ar = $prev_ar;
if(!empty($tmp)) $res_ar = array_unique(array_merge($tmp,$prev_ar));
if($mark) $res_ar = getChildren($tmp,$res_ar,$data, $rem);
return $res_ar;
}
You can use this function in this way:
$data = array( 3 => [4095, 651], 4095 => [3], 651 => [4432], 4432 => [3, 651], 92 => [45], 45 => [92], );
foreach($data as $in => &$data_val) {
$data_val = getChildren([$in],$data_val,$data, $in);
sort($data_val);
}
Demo
Output:
Array
(
[3] => Array
(
[0] => 651
[1] => 4095
[2] => 4432
)
[4095] => Array
(
[0] => 3
[1] => 651
[2] => 4432
)
[651] => Array
(
[0] => 3
[1] => 4095
[2] => 4432
)
[4432] => Array
(
[0] => 3
[1] => 651
[2] => 4095
)
[92] => Array
(
[0] => 45
)
[45] => Array
(
[0] => 92
)
)
Two nested loops over the data. If the keys are different, then check if the key of the inner loop is already contained in the data array of the outer key element - if not, add it.
$data = json_decode('{"3":{"0":4095,"2":651},"4095":[3],"651":[4432],"4432":{"1":651}}', true);
foreach($data as $key_outer => $val_outer) {
foreach($data as $key_inner => $val_inner) {
if($key_outer != $key_inner && !in_array($key_inner, $data[$key_outer])) {
$data[$key_outer][] = $key_inner;
}
}
}
var_dump($data);
This gets you
array (size=4)
3 =>
array (size=3)
0 => int 4095
2 => int 651
3 => int 4432
4095 =>
array (size=3)
0 => int 3
1 => int 651
2 => int 4432
651 =>
array (size=3)
0 => int 4432
1 => int 3
2 => int 4095
4432 =>
array (size=3)
1 => int 651
2 => int 3
3 => int 4095
I am assuming a specific order of the elements in those sub-items is not actually required. If it is, then please sort them yourself as desired afterwards or in between (depending on what exactly you need, f.e. sort($data[$key_outer]); after the inner loop would get you the IDs in all sub-arrays sorted ascending.)

How to set calculate items of loop in one array in PHP

Following is my array
(
[0] => Array
(
[items] => 10.4
[Total] => 10.4
)
[1] => Array
(
[items] => 10.5
[Total] => 10.5
)
[2] => Array
(
[items] => 4.5
[Total] => 15
)
[3] => Array
(
[items] => 15.2
[Total] => 15.2
)
[4] => Array
(
[items] => 8.4
[Total] => 8.4
)
)
Here each array has items & total , I want to check if total of each item is less then 20 then set items with total in a array and also not check already checked item.
For example there are 4 items in array 0 has item 10.4 & total 10.4 then check is less then 20 if not then plus second array item means (10.4 + 10.5) again check if is greater then 20 If yes then set last checked in array like array('item'=>10.4, 'total'=>10.4) , Now second time 10.4 item will skip & check with 10.5 + 4.5 etc...
I want output like.
(
[0] => Array
(
[items] => array([0]=>10.4),
[Total] => 10.4
)
[1] => Array
(
[items] => array(
[0] => 10.5,
[1] => 4.5
),
[Total] => 15
)
[2] => Array
(
[items] => array([0]=>15.2)
[Total] => 15.2
)
[3] => Array
(
[items] => array([0]=>8.4)
[Total] => 8.4
)
)
Following is my script.
$packageInfo = $ordercon->get_package_items_by_order_number($order_number); // Comes from model
// First calculate the total
foreach ($packageInfo as $key => $package) {
$packageInfo[$key]['total_weight'] = $package['quantity'] * $package['weight'];
$packageInfo[$key]['currnt_item'] = $package['quantity'] * $package['weight'];
}
// Then check count the packages ?
$packages = [];
$packageTotalWeight = 0;
$packageItemWeight = 0;
foreach ($packageInfo as $key => $package) {
if(($packageTotalWeight + $package['total_weight']) > 20){
$packages[]['final_total'] = $packageTotalWeight;
$packageTotalWeight = $package['total_weight'];
$data[] = array('items'=>$package['currnt_item'], 'Total'=>$packageTotalWeight); // For combine items
} else {
$packages[]['currntItem'] = $package['quantity'] * $package['weight'];
$packageTotalWeight += $package['total_weight'];
$data[] = array('items'=>$package['currnt_item'], 'Total'=>$packageTotalWeight);
}
}
echo "<pre>";print_r($data);
echo '<pre>packageInfo';print_r($packageInfo);

Find all possible permutations without repeating the value

Let's say I have this set of arrays as input:
[
0 => [1,2,4,5],
1 => [2,3,4],
2 => [1,3],
]
I would like to find all permutations possible selecting one value from each array. That value would be unique in the final result, so it won't repeat. For example, I can't have 1 twice in the result.
The count of arrays on input is the same as count of arrays on output.
Examples of combinations wanted (key=>value):
[0 => 1,1 => 2,2 => 3]
[0 => 2,1 => 3,2 => 1]
[0 => 5,1 => 2,2 => 1]
[0 => 1,1 => 3,2 => null]
Wrong results
[0 => 1,1 => 2,2 => 1]
or
[0 => 2,1 => 2,2 => 3]
I would like to get set of all possible permutations using PHP. How can I do that?
I have attached real data set http://pastebin.com/U6Hyawm4 However, I have no idea how many permutations there may be.
Here's a non-recursive version that's also optimized
/**
* Generates all the possible unique N-tuples from an array of N arrays of integers
*
* #param array $input
* #return array
*/
function generateCombinations(array &$input) {
// since the example results included [1, 3, null] I have assumed that
// null is a possible value of each set.
$sets = [];
foreach($input as $set) {
if(!in_array(null, $set)) {
$set[] = null;
}
$sets[] = $set;
}
// by working on the iterators of each array this loop
// linearizes the entire set of possible combinations
// and iterates it (skipping as many as it can).
$output = [];
$setCount = count($sets);
while(current($sets[0]) !== false) {
$testCombo = [];
for($setIdx = 0; $setIdx < $setCount; $setIdx++) {
if(!in_array(current($sets[$setIdx]), $testCombo)) {
$testCombo[] = current($sets[$setIdx]);
}
else {
// when a combination is thrown out as duplicate
// iterate to skip any other combo's that would also
// contain that duplicate
iterateSets($sets, $setIdx);
break;
}
}
// if there were no duplicates add it to the output and iterate
if(count($testCombo) == $setCount) {
$output[] = $testCombo;
iterateSets($sets, $setCount - 1);
}
}
return $output;
}
/**
* Iterates to the next potentially valid combination. I think of
* this like doing long-hand addition. Add 1 and carry is akin to
* next and reset.
*
* #param array $sets
* #param $index
*/
function iterateSets(array &$sets, $index) {
// reset iterators of all sets past the current one to skip
// combos that cannot be valid
for($i = $index + 1, $ic = count($sets); $i < $ic; $i++) {
reset($sets[$i]);
}
// always move one on current set
next($sets[$index]);
while($index > 0 && current($sets[$index]) === false) {
// wrap if current set is at the end
reset($sets[$index]);
$index--;
// move one for the preceding set
next($sets[$index]);
// then repeat
}
}
The resulting array is:
[
[1,2,3]
[1,2,null]
[1,3,null]
[1,4,3]
[1,4,null]
[1,null,3]
[2,3,1]
[2,3,null]
[2,4,1]
[2,4,3]
[2,4,null]
[2,null,1]
[2,null,3]
[4,2,1]
[4,2,3]
[4,2,null]
[4,3,1]
[4,3,null]
[4,null,1]
[4,null,3]
[5,2,1]
[5,2,3]
[5,2,null]
[5,3,1]
[5,3,null]
[5,4,1]
[5,4,3]
[5,4,null]
[5,null,1]
[5,null,3]
[null,2,1]
[null,2,3]
[null,3,1]
[null,4,1]
[null,4,3]
]
Here's an inefficient version:
$input = array(
[1,2,4,5],
[2,3,4],
[1,3]
);
function appendUnique($subs, $i) {
global $input;
if ($i == count($input)) {
return $subs;
}
$output = array();
foreach ($subs as $sub) {
foreach ($input[$i] as $v) {
$new_sub = array_values($sub);
if (in_array($v, $sub)) {
$new_sub[] = null;
} else {
$new_sub[] = $v;
}
$output[] = $new_sub;
}
}
return appendUnique($output, $i+1);
}
$output = appendUnique([[]], 0);
$output_json = array();
foreach ($output as $row) {
$output_json[] = json_encode($row);
}
$output_json = array_unique($output_json);
$deduped = array();
foreach ($output_json as $json) {
$deduped[] = json_decode($json);
}
print_r($deduped);
outputs:
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] =>
)
[1] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[2] => Array
(
[0] => 1
[1] => 3
[2] =>
)
[3] => Array
(
[0] => 1
[1] => 4
[2] =>
)
[4] => Array
(
[0] => 1
[1] => 4
[2] => 3
)
[5] => Array
(
[0] => 2
[1] =>
[2] => 1
)
[6] => Array
(
[0] => 2
[1] =>
[2] => 3
)
[7] => Array
(
[0] => 2
[1] => 3
[2] => 1
)
[8] => Array
(
[0] => 2
[1] => 3
[2] =>
)
[9] => Array
(
[0] => 2
[1] => 4
[2] => 1
)
[10] => Array
(
[0] => 2
[1] => 4
[2] => 3
)
[11] => Array
(
[0] => 4
[1] => 2
[2] => 1
)
[12] => Array
(
[0] => 4
[1] => 2
[2] => 3
)
[13] => Array
(
[0] => 4
[1] => 3
[2] => 1
)
[14] => Array
(
[0] => 4
[1] => 3
[2] =>
)
[15] => Array
(
[0] => 4
[1] =>
[2] => 1
)
[16] => Array
(
[0] => 4
[1] =>
[2] => 3
)
[17] => Array
(
[0] => 5
[1] => 2
[2] => 1
)
[18] => Array
(
[0] => 5
[1] => 2
[2] => 3
)
[19] => Array
(
[0] => 5
[1] => 3
[2] => 1
)
[20] => Array
(
[0] => 5
[1] => 3
[2] =>
)
[21] => Array
(
[0] => 5
[1] => 4
[2] => 1
)
[22] => Array
(
[0] => 5
[1] => 4
[2] => 3
)
)

PHP array - Sum value of the same key when key are number [duplicate]

This question already has answers here:
PHP Array Group by one field and Sum up two fields [duplicate]
(2 answers)
Closed 4 months ago.
My situation is similar to this thread :
Associative array, sum values of the same key
However in my case all keys are number.
I would like to reduce / combine array where key 0 is similar and make a sum of all other keys.
Here is my original array :
Array
(
[0] => Array
(
[0] => 093042
[1] => 3
[2] => 0
[4] => 0
)
[1] => Array
(
[0] => 222032
[1] => 0
[2] => 13
[4] => 0
)
[2] => Array
(
[0] => 222032
[1] => 0
[2] => 0
[4] => 15
)
[3] => Array
(
[0] => 152963
[1] => 45
[2] => 0
[4] => 0
)
[4] => Array
(
[0] => 222032
[1] => 0
[2] => 7
[4] => 0
)
)
and here is the output i need :
Array
(
[0] => Array
(
[0] => 093042
[1] => 3
[2] => 0
[4] => 0
)
[1] => Array
(
[0] => 222032
[1] => 0
[2] => 20
[4] => 15
)
[2] => Array
(
[0] => 152963
[1] => 45
[2] => 0
[4] => 0
)
)
The solution of other thread is not working because they use the key name and i don't know how i can adapt this to my situation.
Please if you can give me an example of working solution.
REPLY :
For now i try something like that : Take from other thread
$sum = array_reduce($data, function ($a, $b) {
if (isset($a[$b[0]])) {
$a[$b[0]]['budget'] += $b['budget'];
}
else {
$a[$b[0]] = $b;
}
return $a;
});
But this example look is only for key named budget but in my case is number and i have 3 key [1] [2] [3] how can't sum key 1,2,4 where key 0 is similar
This should work for you:
Basically I just loop through your array and check if there is already an element in $result with the key of the first element of $v. If not I initialize it with an array_pad()'ed array of 0's + the current array of the iteration of the foreach loop.
And after this I loop through each element of $v expect the first one and add it to the result array.
At the end I just reindex the result array with array_values().
<?php
foreach($arr as $v){
if(!isset($result[$v[0]]))
$result[$v[0]] = array_pad([$v[0]], count($v), 0);
$count = count($v);
for($i = 1; $i < $count; $i++)
$result[$v[0]][$i] += $v[$i];
}
$result = array_values($result);
print_r($result);
?>
output:
Array
(
[0] => Array
(
[0] => 093042
[1] => 3
[2] => 0
[3] => 0
)
[1] => Array
(
[0] => 222032
[1] => 0
[2] => 20
[3] => 15
)
[2] => Array
(
[0] => 152963
[1] => 45
[2] => 0
[3] => 0
)
)
try this
$data = Array
(
0 => Array
(
0 => 93042,
1 => 3,
2 => 0,
4 => 0,
),
1 => Array
(
0 => 222032,
1 => 0,
2 => 13,
4 => 0,
),
2 => Array
(
0 => 222032,
1 => 0,
2 => 0,
4 => 15,
),
3 => Array
(
0 => 152963,
1 => 45,
2 => 0,
4 => 0,
),
4 => Array
(
0 => 222032,
1 => 0,
2 => 7,
4 => 0,
),
);
var_dump($data);
// grouping
$tab1 = array();
foreach ($data as $e) {
if (!isset($tab1[$e[0]])) {
$tab1[$e[0]] = array();
}
$tab1[$e[0]][] = $e;
}
//var_dump($tab1);
// summing
$tabSum = array();
foreach ($tab1 as $id => $t) {
foreach ($t as $e) {
unset($e[0]);
if (!isset($tabSum[$id])) {
$tabSum[$id] = $e;
} else {
foreach ($e as $key => $value) {
$tabSum[$id][$key] += $value;
}
}
}
}
var_dump($tabSum);

php loop array and update

I have an array and I wish to update the values in roomTotalPrice. However when I loop, it changes to just a variable.
Array I want to change:
Array
(
[10] => Array
(
[12] => Array
(
[num_rooms] => 2
[adults] => Array
(
[0] => 2
[1] => 2
)
[prices] => Array
(
[0] => 44.5
[1] => 44.5
)
[roomTotalPrice] => Array
(
[0] => 44.5
[1] => 44.5
)
[price] => 178
[supp] => 0
)
)
Code I am using:
//Total Room Price
foreach($iroom['roomTotalPrice'] as $irt){
$s_rate[$iraid][$iroid]['roomTotalPrice'] = 100;
}
Array
(
[10] => Array
(
[12] => Array
(
[num_rooms] => 2
[adults] => Array
(
[0] => 2
[1] => 2
)
[prices] => Array
(
[0] => 44.5
[1] => 44.5
)
[roomTotalPrice] => 100
[price] => 178
[supp] => 0
)
)
Use this code:
foreach($iroom['roomTotalPrice'] as &$irt){
$irt = 100;
}
Anyway this code is based on the fact that $iroom['roomTotalPrice'] loop on the right sub-array as you have written.
Are you trying to make the sum for prices ?
$x[10][12][roomTotalPrice] = array_sum($x[10][12][roomTotalPrice])
Assuming that the $iroom variable is the array in your first code sample, I believe you can use the following code to set all 'roomTotalPrice' entries to 100:
foreach ($iroom as $firstLevelIndex => $firstLevelArray) {
foreach ($firstLevelArray as $secondLevelIndex => $secondLevelArray) {
$iroom[$firstLevelIndex][$secondLevelIndex]['roomTotalPrice'] = 100;
}
}
Is this what your want?
foreach ($iroom as $k1 => $v1) { // Loop outer array
foreach ($v1 as $k2 => $v2) if (isset($v2['roomTotalPrice'])) { // Loop inner arrays and make sure they have a roomTotalPrice key
foreach ($v2['roomTotalPrice'] as $k3 => $v3) { // Loop roomTotalPrice array
$iroom[$k1][$k2]['roomTotalPrice'][$k3] = 100; // Change the values
}
}
}

Categories