How to calculate total cost based on price ranges of items - php

I need to calculate total cost of items, based on ranges:
if ($itemCount <11)
{
$cost_for_range = 1;
}
if ($itemCount <26 && $itemCount >=11)
{
$cost_for_range = 0.75;
}
if ($itemCount <50 && $itemCount >=26)
{
$cost_for_range = 0.55;
}
Thing is - I need to count final cost taking earlier levels into consideration - eg if the cart has 30 items, the price would be:
first 10 at $1 = $10
another 15 at $0.75 = $11.25
another 5 at $0.55 = $2.75
so total would be $24.
How to calculate this in php?

Try this :
$itemCount = 25;
$total = 0;
for ( $i = 0 ; $i < $itemCount ; $i++ ) {
if ( $i < 10 ) {
$total += 1;
} else if ( $i < 25 ) {
$total += 0.75;
} else if ( $i < 50 ) {
$total += 0.55;
} else {
$total += 0; // price if more than 50
}
}

Having some fun using min and max to do the various ranges...
function calculateCost ( int $count, float $cost ) {
$total = min(10, $count) * $cost;
$total += (min(15, max(0, $count - 10)) * ($cost * 0.75));
$total += (max(0, $count - 25) * ($cost * 0.55));
return $total;
}
the second calculation uses max(0, $count - 10), so this takes the first 10 off, but ensures it doesn't go negative. Then it uses the min(15, max(0, $count - 10)) to take the lowest of 15 or the number left (so with 30, this will be 15).
The last one is just the max of the count - 25 or 0, so for 30, this is 5.
Use it with...
echo calculateCOst( 30, 1 );
gives 24

For a universal solution, it is good to define the discounts in an array. This solution is then ready for extensions and changes.
$rebate = [10 => 1.0, 15 => 0.75, PHP_INT_MAX => 0.55];
The number and the discount array are transferred to the function that calculates the cost factor. The calculation itself is realized with a simple forech loop with termination condition.
function calcCostFactor(int $count, array $rebate){
$factor = 0.0;
foreach($rebate as $number => $val){
$factor += min($count,$number) * $val;
$count -= $number;
if($count <= 0) break;
}
return $factor;
}
example:
$factor = calcCostFactor(30, $rebate);
Try it self.

Related

PHP Making a variable increment based on another variable's value without having too much code?

i'm trying to increase a variable value depending on the other variable value for example:
i have a variable called $totalhousesleft...
i want to set a price depending on how many $totalhousesleft i have...
everytime the totalhousesleft is down by 10, i want to increase the variable $currentprice by 1.
the starting value of $totalhouses left is 8000 and every time it goes down by 10, i set the $currentprice +1... the starting value of current price is 9...
something like:
If ($totalhousesleft >= 8000) {$currentprice = 9; $sellingprice = 8;}
If ($totalhousesleft >= 7990) {$currentprice = 10; $sellingprice = 9;}
If ($totalhousesleft >= 7980) {$currentprice = 11; $sellingprice = 10;}
If ($totalhousesleft >= 7970) {$currentprice = 12; $sellingprice = 11;}
ALL THE WAY DOWN UNTIL HOUSES LEFT IS 1. If someone can please show me a loop or a shorter code i would really appreciate it!
#elias-soares answer is close, but is missing ceil...and an explanation.
foreach ( [8000, 7995, 7990, 7985, 7980, 7975, 7970, 7965] as $totalhousesleft ) {
$currentprice = 9 + ((ceil(800 - ((min(8000, $totalhousesleft)) / 10))) * 1);
$sellingprice = $currentprice - 1;
}
Try it here: https://onlinephp.io/c/68196
Let's break down how to get $currentprice:
//$currentprice = ceil(9 + (800 - (min(8000, $totalhousesleft) / 10)));
// get the lesser of 8000, or $totalhousesleft
// in other words, 8000 is the maximum number to calculate
$totalhousesleft = min(8000, $totalhousesleft);
// divide total houses left into number of tenth units
$tenth = $totalhousesleft / 10;
// since the price increases when the number of tenth units decreases,
// the unit factor is the difference between the max possible tenths
// and tenths of the current total houses left
$tenthunit = 800 - $tenth;
// tenth unit is fractional for values not evenly divisible by 10,
// so round up
$tenthroundup = ceil($tenthunit);
// multiply the number of tenth units with the price per unit
$pricepertenth = $tenthroundup * 1; // 1 currency per tenth unit
// add the price per tenth cost to the base cost (9 currency)
$currentprice = 9 + $pricepertenth;
Bonus: this can be implemented in a function:
function getPrices ($totalhousesleft, $baseprice = 9, $discount = 1, $priceperunit = 1, $maxtotal = 8000, $units = 10) {
$currentprice = $baseprice + ((ceil(($maxtotal / $units) - ((min($maxtotal, $totalhousesleft)) / $units))) * $priceperunit);
return [$currentprice, $currentprice - $discount];
}
foreach ( [8000, 7995, 7990, 7985, 7980, 7975, 7970, 7965] as $totalhousesleft ) {
list($currentprice, $sellingprice) = getPrices($totalhousesleft);
}
Try it here: https://onlinephp.io/c/2672b
A for or while loop could be used for this. I'd use for:
$iteration = 0;
for($x = 8000; $x > 0; $x = $x - 10){
if(empty($iteration)) {
$iteration = $x/1000;
}
if ($totalhousesleft >= $x) {
$currentprice = $iteration;
$sellingprice = $currentprice + 1;
break;
}
$iteration++;
}
if(empty($currentprice)){
$currentprice = $iteration;
$sellingprice = $currentprice + 1;
}
This iterates over until a match is found then breaks out of the looping. The prices are based on the iteration it is in.
Demo link: https://3v4l.org/Mm432 (updated for edge cases 0-9)
You can use Math.
$currentprice = 9 + (800 - (min(8000,$totalhousesleft)/10));
$sellingprice = $currentprice - 1;

PHP: Price range / average calculation based on historical data

I'm building a little app that analyze ebay historical prices of sold items
and for some keywords/items the range is very wide because the search is too broad or simply wrong, infected by item not properly related
eg.
search prices for iphone the results include either the phone, but
also the charger and accessories/unrelated items which adulterate the prices data...
so i have a range that goes form $5 fro a charger and 500$ for an
iphone
so, given that I will try to improve the search on my side, i'm wondering if there is math calculation to exclude the outliers
say I have
$1200
$549
$399
$519
$9
$599
$549
$9
$499
$399
$519
$99
$5
$5
how to i get the price range to be $300-$600 instead of $10-$800 or so...
her ebelow the current php im using...not sure if is the best
function remove_outliers($dataset, $magnitude = 1)
{
$count = count($dataset);
$mean = array_sum($dataset) / $count; // Calculate the mean
$deviation = sqrt(array_sum(array_map("sd_square", $dataset, array_fill(0, $count, $mean))) / $count) * $magnitude; // Calculate standard deviation and times by magnitude
return array_filter($dataset, function ($x) use ($mean, $deviation) {return ($x <= $mean + $deviation && $x >= $mean - $deviation);}); // Return filtered array of values that lie within $mean +- $deviation.
}
function sd_square($x, $mean)
{
return pow($x - $mean, 2);
}
function calculate_median($arr)
{
sort($arr);
$count = count($arr);
$middleval = floor(($count - 1) / 2);
if ($count % 2) {
$median = $arr[$middleval];
} else {
$low = $arr[$middleval];
$high = $arr[$middleval + 1];
$median = (($low + $high) / 2);
}
return $median;
}
$prices = remove_outliers($prices); //$prices is the array with all the prices stored
$trend = calculate_median($prices);
$trend = round(($trend));
$min = round(min($prices));
$max = round(max($prices));
I find this function useful. The $cleaness variable will give granularity
/**
* Returns an average value from a dirt list of numbers.
*
* #require
*
* $numbers = an array of numbers
* $cleaness = a percentage value
*
* #return integer
* an average value from a cleaner list.
*/
public function CleanAverage ( $numbers, $cleaness ) {
// A
$extremes_to_remove = floor(count($numbers)/100*$cleaness);
if ($extremes_to_remove < 2) {$extremes_to_remove = 2;}
// B
sort ($numbers) ;
// C
//remove $extremes from top
for ($i = 0; $i < ($extremes_to_remove/2); $i++) {
array_pop($numbers);
}
// D
// revers order
rsort($numbers);
// E
//remove $extremes from top
for ( $i = 0; $i < ($extremes_to_remove/2); $i++ ) {
array_pop($numbers);
}
// F
// average
$average = array_sum($numbers)/count($numbers);
return $average;
}

Simple Moving Average in PHP - Error

There seems to be a error in sma calculation in the code below... can someone point out where..
/**
* Simple Moving Average (sma)
*
*A Moving Average is an indicator that shows the average value of a security's price over a period of time. When calculating a moving average, a mathematical analysis of the security's average value over a predetermined time period is made. As the security's price changes,its average price moves up or down.
*
*A simple, or arithmetic, moving average is calculated by adding the closing price of the security for a number of time periods (e.g., 12 days) and then dividing this total by the number of time periods. The result is the average price of the security over the time period. Simple moving averages give equal weight to each daily price.
*
*Formula:
*
* - SUM(Closes of n periods)/n
*/
<?php
$data = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
class sma
{
/**
* #var double[]
*/
private $sma;
/**
* #param double[] $data
* #param int $range
* #return double[]
*/
function get( $data, $range )
{
$position = 0;
while ( empty( $data[ $position ] ) ) {
$position++;
}
$i = $position;
while ( true ) {
if ( empty( $data[ $i + $range - 1 ] ) ) {
break;
}
$temp_sum = 0;
for ( $j = $i; $j < $i + $range; $j++ ) {
$temp_sum += $data[ $j ];
}
$this->sma[ $i + $range - 1 ] = $temp_sum / $range;
$i++;
}
return $this->sma;
}
}
$mysma = new sma();
$mysma->get($data,5); $sma = $mysma->get();
echo mysma;
?>
Also sma calculation in other code seems to be easier.. a few example is here.. if someone has done it in php similarly..??
(defn moving-average
[coll n]
(cond
(< n 1) nil
(= n 1) coll
:else (let [sums (reductions + 0 coll)]
(map #(/ (- %1 %2) n) (drop n sums) sums))))
(time (doall (moving-average coll n)))
# "Elapsed time: 9.184 msecs"
Also this..
double[] MovingAverage(int period, double[] source)
{
var ma = new double[source.Length];
double sum = 0;
for (int bar = 0; bar < period; bar++)
sum += source[bar];
ma[period - 1] = sum/period;
for (int bar = period; bar < source.Length; bar++)
ma[bar] = ma[bar - 1] + source[bar]/period
- source[bar - period]/period;
return ma;
}
Here's a translation based on the last piece of code in your question:
function get(array $data, $range)
{
$sum = array_sum(array_slice($data, 0, $range));
$result = array($range - 1 => $sum / $range);
for ($i = $range, $n = count($data); $i != $n; ++$i) {
$result[$i] = $result[$i - 1] + ($data[$i] - $data[$i - $range]) / $range;
}
return $result;
}

Count the percentage of the number of the current iteration in a foreach loop

I am trying to build up a script that gets the current percentage of the iteration of a loop.
I have :
<?php
$counter = 0;
$total = 100;
foreach($key as value) {
$counter = $counter + 1;
//looping here
$percentage = $counter/total;
}
In my case outputs within the loop for 5 iterations
0.01
0.02
0.03
0.04
0.05
And I need it to output
20
40
60
80
100
To do something like a current percentage completion.
More random exmaples
For 10 loops should be
10
20
30
40
50
60
70
80
90
100
For 100 loops
1
2
.
.
100
For 6 loops
16.6
//brain damaged
Sorry for the noob math php question but I am in a fog today like no days. Thank you and it's much appreciated.
Firstly, you have to get the total amount of iterations. count() helps in this case.
<?php
$counter = 0;
$total = count($yourArray);
// ...
// inside the loop
$counter++;
$percentage = $counter/$total;
Live example
Converting 0.xx to x % is left as an exercise for the reader.
To calculate percentage, you take the current and divide it by the total, then multiply that value by 100, then round it off. I also take the floor value so that 99.7% doesn't round up to 100 since it's not truly complete yet.
for($i=1;$i<=count($yourArray);$i++) {
$percentage = floor(round( (($i / total) * 100), 1 ));
}
Store the total length of the array in a variable and use that to calculate the percentage. Watch that you prefix your variables with $. Also, you might want to name your variables more appropriately—an array isn't a key.
$counter = 0;
$length = count($array);
foreach ($array as $value) {
$counter++;
$percentage = $counter / $length;
}
You can do exactly what are you asking in this way
$counter = 0;
$length = count($array);
foreach ($array as $value) {
$counter=$counter+1;
for ($stepvvx = 10; $stepvvx <= 100; $stepvvx=$stepvvx+10)
{
if ($counter==intval(($length*$stepvvx)/100)){
echo "<br>$stepvvx %";
}
# do your task here
}
you need to do ($total/$iterations) * $counter like this code:
$counter = 0;
$total = 100;
$iterations = count($key);
foreach($key as value) {
$counter++;
$percentage = (($total/$iterations) * $counter)/100;
}

how to find the sum of all the multiples of 3 or 5 below 1000 in php, issue?

i have an small issue with the way this problem is resolved.
some would say: println((0 /: ((0 until 1000).filter(x => x % 3 == 0 || x % 5 == 0))) (_+_)) is the solution witch adds to 233168
my way was to do:
$maxnumber = 1000;
for ($i = 3; $i < $maxnumber; $i += 3)
{
$t += $i;
echo $i.',';
}
echo '<br>';
for ($j = 5; $j < $maxnumber; $j += 5)
{
$d += $j;
echo $j.',';
}
echo '<br>';
echo $t;
echo '<br>';
echo $d;
echo '<br>';
echo $t+$d;
this will give me :
3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69,72,75,78,81,84,87,90,93,96,99,102,105,108,111,114,117,120,123,126,129,132,135,138,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,189,192,195,198,201,204,207,210,213,216,219,222,225,228,231,234,237,240,243,246,249,252,255,258,261,264,267,270,273,276,279,282,285,288,291,294,297,300,303,306,309,312,315,318,321,324,327,330,333,336,339,342,345,348,351,354,357,360,363,366,369,372,375,378,381,384,387,390,393,396,399,402,405,408,411,414,417,420,423,426,429,432,435,438,441,444,447,450,453,456,459,462,465,468,471,474,477,480,483,486,489,492,495,498,501,504,507,510,513,516,519,522,525,528,531,534,537,540,543,546,549,552,555,558,561,564,567,570,573,576,579,582,585,588,591,594,597,600,603,606,609,612,615,618,621,624,627,630,633,636,639,642,645,648,651,654,657,660,663,666,669,672,675,678,681,684,687,690,693,696,699,702,705,708,711,714,717,720,723,726,729,732,735,738,741,744,747,750,753,756,759,762,765,768,771,774,777,780,783,786,789,792,795,798,801,804,807,810,813,816,819,822,825,828,831,834,837,840,843,846,849,852,855,858,861,864,867,870,873,876,879,882,885,888,891,894,897,900,903,906,909,912,915,918,921,924,927,930,933,936,939,942,945,948,951,954,957,960,963,966,969,972,975,978,981,984,987,990,993,996,999
5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180,185,190,195,200,205,210,215,220,225,230,235,240,245,250,255,260,265,270,275,280,285,290,295,300,305,310,315,320,325,330,335,340,345,350,355,360,365,370,375,380,385,390,395,400,405,410,415,420,425,430,435,440,445,450,455,460,465,470,475,480,485,490,495,500,505,510,515,520,525,530,535,540,545,550,555,560,565,570,575,580,585,590,595,600,605,610,615,620,625,630,635,640,645,650,655,660,665,670,675,680,685,690,695,700,705,710,715,720,725,730,735,740,745,750,755,760,765,770,775,780,785,790,795,800,805,810,815,820,825,830,835,840,845,850,855,860,865,870,875,880,885,890,895,900,905,910,915,920,925,930,935,940,945,950,955,960,965,970,975,980,985,990,995
$t - 166833
$d - 99500
and total:
266333
why am i wrong?
Some numbers are multiples of both 3 and 5. (Your algorithm adds these numbers to the total twice.)
Because 6 * 5 == 30 and 10 * 3 == 30, you're adding the some numbers up twice.
$sum = 0;
$i = 0;
foreach(range(0, 999) as $i) {
if($i % 3 == 0 || $i % 5 == 0) $sum += $i;
}
Because you double-count numbers that are multiple of both 3 and 5, i.e. multiples of 15.
You can account for this naively by subtracting all multiples of 15.
for ($j = 15; $j < $maxnumber; $j += 15)
{
$e += $j;
echo $j.',';
}
$total = $total - $d;
In your case, if it is 15, you will add the number twice.
Try this:
$t = 0;
$d = 0;
for ($i = 0; $i <= $maxnumber; $i++){
if ($i % 3 == 0)
$t+= $i;
else if ($i % 5 == 0)
$d += $i;
}
echo $t.'<br>'.$d;
I think that in your code, if a number is a multiple of 3 and 5, it is added twice. Take 15 for example. It's in your list of multiples of 3 and in the list of multiples of 5. Is this the behaviour you want?
One of the best approach to this solution (to achieve optimum time complexity), run an Arithmetic Progression series and find the number of terms in all series by using AP formula: T=a+(n-1)d, then find sum by : S=n/2[2*a+(n-1)d]
where : a=first term ,n=no. of term , d=common deference, T=nth term
The code solution below has been implemented to suit the question above - so the values 3 and 5 are hard-coded. However, the function can modified such that values are passed in as variable parameters.
function solution($number){
$val1 = 3;
$val2 = 5;
$common_term = $val1 * $val2;
$sum_of_terms1 = calculateSumofMulitples($val1,$number);
$sum_of_terms2 = calculateSumofMulitples($val2,$number);
$sum_of_cterms = calculateSumofMulitples($common_term,$number);
$final_result = $sum_of_terms1 + $sum_of_terms2 - $sum_of_cterms;
return $final_result;
}
function calculateSumofMulitples($val, $number)
{
//first, we begin by running an aithmetic prograssion for $val up to $number say N to get the no of terms [using T=a +(n-1)d]
$no_of_terms = (int) ($number / $val);
if($number % $val == 0) $no_of_terms = (int) ( ($number-1)/$val ); //since we are computing for a no of terms below N and not up to/exactly/up to N. if N divides val with no remainder, use no of terms = (N-1)/val
//second, we compute the sum of terms [using Sn = n/2[2a + (n-1)d]
$sum_of_terms = ($no_of_terms * 0.5) * ( (2*$val) + ($no_of_terms - 1) * $val );
// sum of multiples
return $sum_of_terms;
}
You can run a single loop checking whether the number is multiple of 3 OR 5:
for ($i = 0; $i < $maxnumber; $i++)
{
if($i%3 || $i%5){
$t += $i;
echo $i.',';}
}
I think the original code is not including numbers which are multiples of both 3 and 5 in the total: if the test for multiple of 3 matches, it takes that and goes on.
If you total the multiples of 15 up to 1000, you get 33165, which is exactly the difference between your total, 266333, and the original total, 233168.
Here's my solution to the question:
<?php
$sum = 0;
$arr = [];
for($i = 1; $i < 1000; $i++){
if((int)$i % 3 === 0 || (int)$i % 5 === 0)
{
$sum += $i;
array_push($arr,$i);
}
}
echo $sum;
echo '<br>';
print_r($arr);//Displays the values meeting the criteria as an array of values

Categories