Determine and do stuff in foreach loop except the last iteration - php

I am looping a foreach and i need to make some logic like this:
if the iteration is not the last. Gather up the prices. when the iteration is the last. subtract from the total with the gathered up prices. except the last iteration price. I got the following code not. but it's not working.
$i = 0;
$credit = '';
$count = count($reslist);
foreach ($reslist as $single_reservation) {
//All of the transactions to be settled by course
//$credit = $this->Reservations_model->find_res_price($single_reservation['value']) * $this->input->post('currency_value');
if ($i > $count && $single_reservation != end($reslist)) {
$gather_sum_in_czk += $this->Reservations_model->find_res_price($single_reservation['value']) * $this->input->post('currency_value');
$credit = $this->Reservations_model->find_res_price($single_reservation['value']) * $this->input->post('currency_value');
}
//Last iteration need to subtract gathered up sum with total.
else {
$credit = $suminczk - $gather_sum_in_czk;
}
$i++;
}
EDIT: TRYING TO GATHER UP PRICES FOR ALL INTERACTIONS EXECPT LAST:
if ($i != $count - 1 || $i !== $count - 1) {
$gather_sum_in_czk += $this->Reservations_model->find_res_price($single_reservation['value']) * $this->input->post('currency_value');
$credit = $this->Reservations_model->find_res_price($single_reservation['value']) * $this->input->post('currency_value');
}
else {
$credit = $suminczk - $gather_sum_in_czk;
}

The SPL CachingIterator is always one element behind its inner iterator. It can therefore report whether it will produce a next element via ->hasNext().
For the example I'm choosing a generator to demonstrate that this approach doesn't rely on any additional data like e.g. count($array).
<?php
// see http://docs.php.net/CachingIterator
//$cacheit = new CachingIterator( new ArrayIterator( range(1,10) ) );
$cacheit = new CachingIterator( gen_data() );
$sum = 0;
foreach($cacheit as $v) {
if($cacheit->hasNext()) {
$sum+= $v;
}
else {
// ...and another operation for the last iteration
$sum-=$v;
}
}
echo $sum; // 1+2+3+4+5+6+7+8+9-10 = 35
// see http://docs.php.net/generators
function gen_data() {
foreach( range(1,10) as $v ) {
yield $v;
}
}

foreach-ing an array in PHP returns both the key (integer index if pure array) and value. To be able to use the value, use the following construct:
foreach ($array as $key => $value) {
...
}
then you can check whether $key >= count($array) - 1 (remember in a 0-based array, the last element is count($array) - 1.
Your original code almost works, just wrong in the if condition. Use $i >= $count - 1 instead of $i > $count.

Related

how to get sum of dynamic values from array

I have a list of requested items that are pulled from the database. What I am looking to do is to get the hourly_rate for each item that is selected and add those values together. I am getting the values I need from the database, but now I am looking to add those values.
//Get total hours from other query
$hours = $row['total_hours'];
//Items requested by user
$requestedItems = "1,2,3";
$items = explode(',', $requestedItems);
//Query
$priceQuery = "SELECT hour_rate,
day_rate,
item_id,
rental_status,
hourly_rental
FROM
products
WHERE
rental_status != 1
AND
item_id = :var
";
$itemDisplay = array();
I loop through and get back the values, but now what I want is to add those returned values together...I tried turning them to integers and adding them together but could not seem to do it.
foreach($items as $var){
$itemDisplay = $userFile->priceSelection($conn, $var, $priceQuery);
foreach($itemDisplay as $key=>$v){
//Edits added
$itemVar += $v['hour_rate'];
if($hours >= 3){
if($v['hourly_rental'] == '1'){
$hours -= 2;
$itemVar += $v['day_rate'] * $hours;
}else{
$itemVar += $v['day_rate'];
}
}else{
if($v['hourly_rental'] == '1'){
$itemVar += $v['day_rate'];
}else{
// This is the line here that is affecting the value of both items.
//If $day_rate = $v['day_rate'] then the items with hourly_rentals == '1'
//have correct values. If I set $day_rate = 0; then the items with
//hourly_rentals != '1' have correct values
//but not both at the same time. Might need to figure out a better comparison.
$day_rate = $v['day_rate'];
print_r($day_rate);
}
}
}
}
$totalPrice = $itemVar + $day_rate + $delivery_cost;
The price selection function just grabs the values from database (code for clarity)
public function priceSelection($conn, $var, $priceQuery){
$stmt = $conn->prepare($priceQuery);
$stmt->bindParam(":var", $var);
$stmt->execute();
$result = $stmt->fetchAll();
if($stmt->rowCount() > 0){
foreach($result as $row){
$array[] = $row;
}
return $array;
}
return false;
}
Beside the option to Summarize the numbers within the SQL query you may do it in PHP as well.
Avoid resetting the value on each loop step and continuously add the value to $itemVar variable:
<?php
foreach($items as $var){
$itemDisplay = $userFile->priceSelection($conn, $var, $priceQuery);
foreach($itemDisplay as $key=>$v){
//$itemVar = ''; // do not null the sum value
//Items returned that I would like to be added together
$itemVar += $v['hour_rate'];
//$values = intval($itemVar);
}
}
print_r($itemVar); // print final value
EDIT after OP update
I see two issues in the updated OP code.
the data in the variable $day_rate is set directly and only within the nested foreach loop so this variable keeps the very last value that is set each time the else - else condition is met AND it is the only place where the variable is initiated. This could make some troubles in final calculation.
the $itemVar variable is incrementally calculating its total sum in each loop however the $day_rate is not and more over the problem mentioned in first point. You may need to make a sum of that value as well what you can achieve with this: $day_rate = $v['day_rate'];
potential problem might be the comparison of (xxx == '1') as the PHP dynamically works with the variable entity it will take and convert the value of xxx to most probable to an integer and then converts the string of '1' to the integer as well befor the comparison is made. As an example gues how is compared var_dump(true == '1'); true or false, huh?
Note it is going to be XY problem since the whole structure starts not making any sense to me.
Last EDIT
As general purpose tip for understanding what your code is doing I would recommend any kind of debugger where you can see live status of any variable while the script is processing. Debugging in PHP
Or very simple way of debugging that is simple printing the variable content so you can get at least some idea how to data are calculated.
And of course Always debug your scripts with enabled PHP Error Reporting!
// Counters for
$itemsCounter = 0;
$displayCounter = 0;
foreach($items as $var){
$itemDisplay = $userFile->priceSelection($conn, $var, $priceQuery);
foreach($itemDisplay as $key=>$v){
// Debug current variables rows and $v
echo "Row $itemsCounter::$displayCounter; key=$key;". print_r($v, true);
//Edits added
$itemVar += $v['hour_rate'];
if($hours >= 3){ // WHERE do you get the $hours? Sould it be $v['hour_rate']?
if($v['hourly_rental'] == '1'){
$hours -= 2;
$itemVar += $v['day_rate'] * $hours;
}else{
$itemVar += $v['day_rate'];
}
// Debug current variable $itemVar
echo "itemVar=$itemVar;"
}else{
if($v['hourly_rental'] == '1'){
$itemVar += $v['day_rate'];
}else{
$day_rate = $v['day_rate'];
print_r($day_rate);
}
// Debug current variable $itemVar and new $day_rate
echo "itemVar=$itemVar;day_rate=$day_rate;"
}
$displayCounter++; // iterrate the inner counter
}
// iterrate the counter
$itemsCounter++;
// reset the inner counter for next loop
$displayCounter = 0;
// Debug inserts new line
echo PHP_EOL;
}
$totalPrice = $itemVar + $day_rate + $delivery_cost;
Maybe you just get the amount, it will solve your problem?
$sumHourlyRental = "SELECT SUM(hourly_rental) FROM products WHERE rental_status != 1 AND item_id = :var";
So to answer my own question, I needed to actually do the calculations within the function itself. It works as intended now
//Code on schedule.php page
//Find how many requested items there are
$items = explode(',', $requestedItems);
$item_name = array();
foreach ($items as $var){
$item_name[] = $products->priceChange($conn, $var, $hours);
}
$prices = 0;
foreach($item_name as $price){
$prices += $price;
}
$prices += $delivery_cost;
echo '<button type="button" class="btn" style="color:green;font-weight:bold;">$'.$prices.'</button>';
Then in the function, I added up the values.
public function priceChange($conn, $var, $hours){
$query = "SELECT * FROM products WHERE item_id = :id";
$stmt = $conn->prepare($query);
$stmt->bindParam(":id", $var);
$stmt->execute();
$result = $stmt->fetchAll();
if($stmt->rowCount() > 0){
$total = 0;
foreach($result as $row){
$hour_rate = $row['hour_rate'];
$day_rate = $row['day_rate'];
if($hours == '2'){
$total += $hour_rate;
}else{
if($row['hourly_rental'] == '1'){
$hours -= 2;
$total += $hour_rate + $day_rate * $hours;
}
else{
$total = $hour_rate + $day_rate;
}
}
}
return $total;
}
return false;
}

Reverse the output in a script that reads data in an external xml file

I have a script that reads values in an external XML file using PHPExcel.php, then it prints results reading the last time a number is $extraset is found into the XML file.
My problem : i should reverse the way the script calculates the result, since my values go from the newer to the older.
Example : if the 10 value appears in row 2 and then in row 6, correct result should be : 10 appears in row 2. At the moment I get '10 appears in row 10'.
Is there a way to reverse the way phpexcel read the file ? Or maybe i can just reverse the way values are processed ? Here is the script :
<?php
require_once "Classes/PHPExcel.php";
$path = "original_source.xls";
$reader = PHPExcel_IOFactory::createReaderForFile($path);
$excel_Obj = $reader->load($path);
//Get the last sheet in excel
//$worksheet=$excel_Obj->getActiveSheet();
//Get the first sheet in excel
$worksheet=$excel_Obj->getSheet('0');
$lastRow = $worksheet->getHighestRow();
$columncount = $worksheet->getHighestDataColumn();
$columncount_number = PHPExcel_Cell::columnIndexFromString($columncount);
$row_start = 6;
$row_end = 26;
$col_start = 2; //Index of column - C
$col_end = 21; //Index of column - V
$sets = array();
for ($row = 0; $row <= $lastRow; $row++) {
$set = array();
for ($col = 0; $col <= $columncount_number; $col++) {
if ($row >= $row_start && $row <= $row_end && $col >= $col_start && $col <= $col_end) {
array_push($set, $worksheet->getCell(PHPExcel_Cell::stringFromColumnIndex($col).$row)->getValue());
}
else if ($row > $row_end) {
break;
}
}
if ($row >= $row_start && $row <= $row_end) {
array_push($sets, $set);
}
else if ($row > $row_end) {
break;
}
}
//echo '<pre>'; print_r($sets); die;
$extraset = ['113', '15', '313'];
$reverse_sets = array_reverse($sets);
foreach ($extraset as $element) {
foreach ($reverse_sets as $index => $set) {
if (in_array($element, $set)) {
$actual_index = count($reverse_sets)-$index-1;
echo "Extraset element '$element' is in set $actual_index<br>";
break;
}
}
}
?>
I was trying with array_reverse, but I only keep getting 'error 500'. I'm a bit confused.
Thanks for your help
EDIT :
The modify i did with array reverse was to remove the array reverse function, changing that part in this way, and it works properly :
foreach ($extraset as $element) {
foreach ($sets as $index => $set) {
if (in_array($element, $set)) {
$actual_index = count($sets)-$index-1;
echo "Extraset element '$element' is in set $actual_index<br>";
break;
}
}
}
?>
Now the script outputs me the right value, but what I can't fix is the way $actual_index works.
This is my actual output :
Extraset element '113' is in set 0
Extraset element '15' is in set 20
Extraset element '313' is in set 20
My problem :
The way it search the values is correct, but is wrong the way it calculates the set. Set 0 should be set 20, while set 20 should be set 0.

How to grade scores in php

I'm trying to grade some scores according to highest average obtained..
Here's my scripts
$scores_AND_ID = 'M2377O=100,M2727B=100,M5821K=100,M7492F=97.75,M7973O=96,M3487I=94,M7969O=93.13,M1452V=92.5,M4653O=92.38,M4158J=92.25,M2881A=89.38,M6112S=28.63,';
$out_score = chop($scores_AND_ID, ',');
$rr2 = explode(",", $out_score);
$array_un = array_unique($rr2);
foreach ($array_un as $key => $value) {
if ($value == "") {
continue;
}
$postion = positionNumbers($key);//1st,2nd,3rd function
$sec = explode("=", $value);
rsort($sec);
$stdntID = $sec[0]; //Student number
$stdntAV = $sec[1]; //Student Average
mysql_query("UPDATE score_table SET grade='$postion' WHERE avg='$stdntAV' ");
}
I'm using foreach key to assign grade position but isn't working properly.
Here's my result
Here's what I need to achieve.
1. 100---1st
2. 100---1st
3. 100---1st
4. 98---4th
5. 89.5--5th
6. 89---6th
7. 89---6th
8. 80---8th
Thanks Guys
I think the code you want is this:
<?php
$scores_AND_ID = 'M7492F=97.75,M7973O=96,M3487I=94,M2377O=100,M2727B=100,M5821K=100,M7969O=93.13,M1452V=92.5,M4653O=92.38,M4158J=92.25,M2881A=89.38,M6112S=28.63,';
// Gets all of the entries from the source string
$scores_array = array_unique(array_filter(explode(',', $scores_AND_ID)));
// Sets up an associative array of values (student id => score)
$score_map = [];
foreach ($scores_array as $record) {
[ $student_id, $score ] = explode('=', $record);
$score_map[$student_id] = $score;
}
// Ensure values are sorted numerically descending
uasort($score_map, function ($a, $b) {
if ($a > $b) {
return -1;
}
if ($a == $b) {
return 0;
}
return 1;
});
// Gets the maximum value from the scores
$previous_score = max(array_values($score_map));
$rank = 1;
$incrementer = 0;
foreach ($score_map as $student => $score) {
// If the score hasn't changed from it's previous value
// we increment a counter instead of the rank
if ($score == $previous_score) {
$incrementer++;
// Once it's changed, we update the rank based on the incrementer
// and then reset the incrementer
} else {
$rank += $incrementer;
$incrementer = 1;
}
$previous_score = $score;
// Updating database is left as an exercise to the reader
}
You should not update your records if grade is already set. If you print your query instead of executing it you will see that you set grade 1st, then you overwrite it with 2nd and then with 3rd.

Get lowest price on sum of combinations in given array

This code is working fine when the array length is 8 or 10 only. When we are checking this same code for more than 10 array length.it get loading not showing the results.
How do reduce my code. If you have algorithm please share. Please help me.
This program working flow:
$allowed_per_room_accommodation =[2,3,6,5,3,5,2,5,4];
$allowed_per_room_price =[10,30,60,40,30,50,20,60,80];
$search_accommodation = 10;
i am get subsets = [5,5],[5,3,2],[6,4],[6,2,2],[5,2,3],[3,2,5]
Show lowest price room and then equal of 10 accommodation; output like as [5,3,2];
<?php
$dp=array(array());
$GLOBALS['final']=[];
$GLOBALS['room_key']=[];
function display($v,$room_key)
{
$GLOBALS['final'][] = $v;
$GLOBALS['room_key'][] = $room_key;
}
function printSubsetsRec($arr, $i, $sum, $p,$dp,$room_key='')
{
// If we reached end and sum is non-zero. We print
// p[] only if arr[0] is equal to sun OR dp[0][sum]
// is true.
if ($i == 0 && $sum != 0 && $dp[0][$sum]) {
array_push($p,$arr[$i]);
array_push($room_key,$i);
display($p,$room_key);
return $p;
}
// If $sum becomes 0
if ($i == 0 && $sum == 0) {
display($p,$room_key);
return $p;
}
// If given sum can be achieved after ignoring
// current element.
if (isset($dp[$i-1][$sum])) {
// Create a new vector to store path
// if(!is_array(#$b))
// $b = array();
$b = $p;
printSubsetsRec($arr, $i-1, $sum, $b,$dp,$room_key);
}
// If given $sum can be achieved after considering
// current element.
if ($sum >= $arr[$i] && isset($dp[$i-1][$sum-$arr[$i]]))
{
if(!is_array($p))
$p = array();
if(!is_array($room_key))
$room_key = array();
array_push($p,$arr[$i]);
array_push($room_key,$i);
printSubsetsRec($arr, $i-1, $sum-$arr[$i], $p,$dp,$room_key);
}
}
// Prints all subsets of arr[0..n-1] with sum 0.
function printAllSubsets($arr, $n, $sum,$get=[])
{
if ($n == 0 || $sum < 0)
return;
// Sum 0 can always be achieved with 0 elements
// $dp = new bool*[$n];
$dp = array();
for ($i=0; $i<$n; ++$i)
{
// $dp[$i][$sum + 1]=true;
$dp[$i][0] = true;
}
// Sum arr[0] can be achieved with single element
if ($arr[0] <= $sum)
$dp[0][$arr[0]] = true;
// Fill rest of the entries in dp[][]
for ($i = 1; $i < $n; ++$i) {
for ($j = 0; $j < $sum + 1; ++$j) {
// echo $i.'d'.$j.'.ds';
$dp[$i][$j] = ($arr[$i] <= $j) ? (isset($dp[$i-1][$j])?$dp[$i-1][$j]:false) | (isset($dp[$i-1][$j-$arr[$i]])?($dp[$i-1][$j-$arr[$i]]):false) : (isset($dp[$i - 1][$j])?($dp[$i - 1][$j]):false);
}
}
if (isset($dp[$n-1][$sum]) == false) {
return "There are no subsets with";
}
$p;
printSubsetsRec($arr, $n-1, $sum, $p='',$dp);
}
$blockSize = array('2','3','6','5','3','5','2','5','4');
$blockvalue = array('10','30','60','40','30','50','20','60','80');
$blockname = array("map","compass","water","sandwich","glucose","tin","banana","apple","cheese");
$processSize = 10;
$m = count($blockSize);
$n = count($processSize);
// sum of sets in array
printAllSubsets($blockSize, $m, $processSize);
$final_subset_room = '';
$final_set_room_keys = '';
$final_set_room =[];
if($GLOBALS['room_key']){
foreach ($GLOBALS['room_key'] as $set_rooms_key => $set_rooms) {
$tot = 0;
foreach ($set_rooms as $set_rooms) {
$tot += $blockvalue[$set_rooms];
}
$final_set_room[$set_rooms_key] = $tot;
}
asort($final_set_room);
$final_set_room_first_key = key($final_set_room);
$final_all_room['set_room_keys'] = $GLOBALS['room_key'][$final_set_room_first_key];
$final_all_room_price['set_room_price'] = $final_set_room[$final_set_room_first_key];
}
if(isset($final_all_room_price)){
asort($final_all_room_price);
$final_all_room_first_key = key($final_all_room_price);
foreach ($final_all_room['set_room_keys'] as $key_room) {
echo $blockname[$key_room].'---'. $blockvalue[$key_room];
echo '<br>';
}
}
else
echo 'No Results';
?>
I'm assuming your task is, given a list rooms, each with the amount of people it can accommodate and the price, to accommodate 10 people (or any other quantity).
This problem is similar to 0-1 knapsack problem which is solvable in polynomial time. In knapsack problem one aims to maximize the price, here we aim to minimize it. Another thing that is different from classic knapsack problem is that full room cost is charged even if the room is not completely occupied. It may reduce the effectiveness of the algorithm proposed at Wikipedia. Anyway, the implementation isn't going to be straightforward if you have never worked with dynamic programming before.
If you want to know more, CLRS book on algorithms discusses dynamic programming in Chapter 15, and knapsack problem in Chapter 16. In the latter chapter they also prove that 0-1 knapsack problem doesn't have trivial greedy solution.

php - while loop is itering double the times expected and nested for loop is iterating 1.5 times more than expected

This script is supposed to to get a multidimensional array and iterate through the values.
The array size is 10 and each element should contain an associative array:
$games[0] => array('foo' => 'bar')
$games[1] => array('foo1' => 'bar1')
etc..
The while loop should iterate 5 times in this example. The for loop should iterate 10 times for each iteration of the while loop.
So I am expecting the echo to be:
countwhile = 5 countfor = 50 totalgames = 50
but im actually getting
countwhile = 5 countfor = 150 totalgames = 150
I believe $games array is not the problem because i have have made that call below before and have used print_r to view the contents and it is as expected.
This whole code is not in a function or class just as is on my index.php page, could the problem be to do with the variable scopes?
$totalruns = 5;
$endindx = 10;
$startindx = 0;
$countwhile = 0;
$countfor = 0;
$totalfilesize = 0;
$totalgames = 0;
$sizeof = 0;
while($totalruns > 0)
{
$games = $feedHandler->getGames($startindx, $endindx);
$sizeof = sizeof($games);
for($i=0; $i<$sizeof; $i++)
{
$totalfilesize += $games[$i]['swf_file_size'];
$countfor++;
}
$startindx += 10;
$endindx += 10;
$totalruns -= 1;
$totalgames += $sizeof;
unset($games);
}
echo'<p>' . ' countwhile = ' . $countwhile . ' countfor = ' . $countfor . '</p>';
problem 1:
$sizeof = sizeof($games)-1;
explain 1:
for($i=0, $sizeof = sizeof($games);$i<=$sizeof;$i++)
the above will execute 11 times is the sizeof($games) is 10
So, either
for($i=1, $sizeof = sizeof($games);$i<=$sizeof;$i++)
or
for($i=0, $sizeof=sizeof($games)-1;$i<=$sizeof;$i++)
problem 2 :
$e = sizeof($games);
explain 2 :
$e = count($games);
...
$e += $e;
If the final size of $games is 50, you just sum it to 100
so, it some kind of logic problem
I know the answer has been accepted, but thought I'd refactor and make this a little more clean.
function retrieveGamesInfo($limit, $start = 0)
{
$feedHandler = new FeedHandler(); // ignore this, just for testing to simluate your call
if ($start > $limit)
throw new Exception("Start index must be within the limit");
$result = Array(
'TotalGames' => 0,
'TotalFileSize' => 0
);
// iterate over the results in groups of 10
$range = $start;
while ($range < $limit)
{
$range_end = $range + 10; // change me to play with the grab amount
if ($range_end > $limit)
$range_end = $limit;
// grab the next 10 entries
$games = $feedHandler->getGames($range,$range_end);
$result['TotalGames'] += count($games);
foreach ($games as $game)
$result['TotalFileSize'] += $game['swf_file_size'];
$range = $range_end;
}
return $result;
}
var_dump(retrieveGamesInfo(50));
based one everything I've read and taken in, this should be a good supplement. The above provides the following result:
array(2) {
["TotalGames"]=>
int(50)
["TotalFileSize"]=>
int(275520)
}
As i said in my comment $e is overwritten at each loop, so what you have in $e at the end is just the last count of elements in $games *2.
Added with ajreal issues this means results are what your code is expected to render :-) and I'm quite sure your last $game is not just 10 elements but 50. Quiet sure... but it's hard to read.

Categories