Look for a more elegant solution for this cycle.

I tried to ask about it earlier, but I don’t think I formulated the question correctly, so I worked out what brought me the result that I was after, and now I hope this helps me to help.

Problem: I have 10 items. If you buy 1, then 10 dollars. I am selling you a second for $ 9. I am selling you a third item for $ 8. I will continue to withdraw money until we get to $ 5 / item, because it is the lowest I will sell it for. So, if you buy all 10, it will cost you $ 65.

This is the pricing model I'm trying to achieve, with the exception of a much larger scale. Instead of a few items using dollars, I'm talking about millions and using fractions of coins.

This is my current code:

<?php 

function getCost($num_items)
{
    $min_price            = 0.002;
    $max_price            = 0.007;
    $discount_range       = 1000000;

    $discount_per_additional_item = ($max_price - $min_price) / ($discount_range - 1);

    $price_per_unit = MAX($min_price, ($max_price - ($num_items - 1) * $discount_per_additional_item) );

    return $price_per_unit;
}

$array = [100, 1000, 10000, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000];

foreach ($array as $value)
{

    $sum = 0;
    for ($i = 0; $i < $value; ++$i)
        $sum += getCost($i);

    echo number_format($value) . '  |  $' . number_format($sum) . "\n";

}

Result:

100  |  $1
1,000  |  $7
10,000  |  $70
100,000  |  $675
200,000  |  $1,300
300,000  |  $1,875
400,000  |  $2,400
500,000  |  $2,875
600,000  |  $3,300
700,000  |  $3,675
800,000  |  $4,000
900,000  |  $4,275
1,000,000  |  $4,500

I use $ array as a health check, where in the real world I would just calculate the actual number that the client is charged to.

My question is: is there a way to do this without using a for loop? Something maybe more elegant?

I made an online example: http://sandbox.onlinephpfunctions.com/code/47e270dbad8cbe16c9ea906ffd2dce098a52fbca

+4
source share
2 answers

This code will have the same output and has no inner loop:

$min_price            = 0.002;
$max_price            = 0.007;
$discount_range       = 1000000;
$discount_per_additional_item = ($max_price - $min_price)/($discount_range - 1);

$num_progressively_discounted_items = 
        ceil(($max_price - $min_price) / $discount_per_additional_item);
foreach ($array as $value) {
    $num_items_above_min = min($value, $num_progressively_discounted_items);
    $num_items_at_min = $value - $num_items_above_min; 
    $sum = $num_items_at_min * $min_price + 
           $num_items_above_min * $max_price - 
           $discount_per_additional_item 
               * $num_items_above_min * ($num_items_above_min - 1)/2;

    echo number_format($value) . '  |  $' . number_format($sum) . "\n";
}

This is what it does:

  • , . , , , .
  • ( ) : .
  • . ​​ , , .
  • : , , 0+1+2+3+4+5...+n. : n(n-1)/2.

, - : $i=0 , getCost($i), , . , $i=1. , , , . , .

+4

:

function sumOfNaturalSeries($n)
{
    return ((1 + $n) / 2) * $n;
}

$minPrice = 0.002;
$maxPrice = 0.007;
$discountRange = 1000000;

$discountStep = ($maxPrice - $minPrice) / $discountRange;

$getPrice = function ($numberOfItems) use (
    $minPrice,
    $maxPrice,
    $discountRange,

    $discountStep
) {
    if ($numberOfItems <= $discountRange) {
        return $maxPrice * $numberOfItems - sumOfNaturalSeries($numberOfItems - 1) * $discountStep;
    }

    $itemsAboveRange = $numberOfItems - $discountRange;

    return $maxPrice * $discountRange - sumOfNaturalSeries($discountRange - 1) * $discountStep + $minPrice * $itemsAboveRange;
};

$array = [100, 1000, 10000, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000];

$sums = array_map($getPrice, $array);

var_dump($sums);
var_dump(array_map('number_format', $sums));

.

.

0

All Articles