简体   繁体   English

寻找更优雅的解决方案

[英]Looking for a more elegant solution to this loop

I tried asking this earlier, but I don't think I phrased the question correctly so I worked out something that got me the result I was after and now am hoping that it will help someone help me. 我之前尝试过这个问题,但我认为我没有正确地提出这个问题,所以我找到了一些能让我得到结果的东西,现在我希望能帮助别人帮助我。

Problem: I have 10 items. 问题:我有10件物品。 If you buy 1, it's $10. 如果你买1,那就是10美元。 I will sell you the second one for $9. 我会以9美元的价格卖给你第二个。 I will sell you the third item for $8. 我会以8美元的价格卖给你第三件商品。 I will keep taking off money until we get to $5/item because that is the lowest I will sell it for. 我将继续取钱,直到我们达到5美元/项目,因为这是我将出售的最低价格。 So, if you buy all 10, it will cost you $65. 所以,如果你全部买10,那么你将花费65美元。

This is the pricing model I am trying to achieve, except at a much larger scale. 这是我试图实现的定价模型,除了规模要大得多。 Instead of a handful of items using dollars, I'm talking about up to millions and using fractions of pennies. 而不是使用美元的少数项目,我谈论的数百万和使用几分钱。

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";

}

Which results in: 结果如下:

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'm using $array as a sanity check where in the real world, I would simply calculate for the actual number the customer is being charged for. 我正在使用$ array作为一个完整性检查,在现实世界中,我只是计算客户收取的实际数量。

My question is: Is there a way to accomplish this without using a for loop? 我的问题是:有没有办法在不使用for循环的情况下完成此操作? Something, perhaps, more elegant? 或许更优雅的东西?

I made an example online: http://sandbox.onlinephpfunctions.com/code/47e270dbad8cbe16c9ea906ffd2dce098a52fbca 我在网上做了一个例子: http//sandbox.onlinephpfunctions.com/code/47e270dbad8cbe16c9ea906ffd2dce098a52fbca

This code will have the same output, and does not have the 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: 这就是它的作用:

  • It first checks how many times the unit discount can be subtracted from the original price before hitting the minimum price. 它首先检查在达到最低价格之前可以从原始价格中减去单位折扣的次数。 If more than the number of items you are buying, then this calculated figure is corrected to that number of items. 如果超过您购买的商品数量,则将此计算的数字更正为该项目数。
  • The remaining number of items (if any) are also taken note of: these will all have the minimum price. 剩余的物品数量(如果有的话)也被注意到:这些物品都有最低价格。
  • The sum consists of two parts. 总和由两部分组成。 The easy part is represented by the number of items that will go for the minimum price, and it is a simple multiplication. 简单部分由最低价格的项目数量表示,它是一个简单的乘法。
  • The second part of the sum consists of an always decreasing term, or otherwise put: it is the maximum price for the number of items that don't go for the minimum price, minus the sum of 0+1+2+3+4+5...+n . 总和的第二部分包括一个总是递减的期限,或以其他方式放置:它是没有达到最低价格的项目数的最大价格减去0+1+2+3+4+5...+n的总和0+1+2+3+4+5...+n For that the formula is known: n(n-1)/2 . 为此,公式是已知的: n(n-1)/2

Like I mentioned in comments, there is something strange in your code: for $i=0 the value returned by getCost($i) is higher than the max price, as the unit discount gets added to it. 就像我在评论中提到的那样,你的代码中有一些奇怪的东西:对于$i=0getCost($i)返回的值高于最高价格,因为单位折扣被添加到它。 This can be corrected by starting your inner loop with $i=1 . 这可以通过使用$i=1启动内部循环来纠正。 Anyway, this means there is a tiny difference in the result of my proposed code, as it does not have this peculiarity. 无论如何,这意味着我提出的代码的结果有微小的差异,因为它没有这种特性。 But as the discount per unit is so tiny, you don't actually notice it in the printed output. 但由于每单位折扣非常小,因此您在打印输出中实际上并未注意到它。

You can do this a little bit more functional style : 你可以这样做一点功能风格

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));

Here is demo . 这是演示

Take a notice on computational error. 注意计算错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM