从反射范围的数组中选取最接近的值

时间:2010-10-27 11:33:23

标签: php arrays

我有一个反映折扣百分比的数组,具体取决于订购的商品数量:

$rebates = array(
   1 => 0,
   3 => 10,
   5 => 25,
  10 => 35)

意味着对于一件或两件物品,你没有得到回扣;对于3个以上的项目,您获得10%,5个以上的项目获得20%,10 + 35%以上等等。

是否有优雅,单行方式获得任意数量项目的正确回扣百分比,比如7

显然,这可以通过一个简单的循环来解决:这不是我想要的。我很感兴趣是否有一个我不知道的核心数组或其他功能可以更优雅地做到这一点。

  

我要把接受的答案奖励给200分,但显然,我必须等待24小时,直到我能做到这一点。问题解决了。

4 个答案:

答案 0 :(得分:16)

这是另一个,一点也不短。

$percent = $rebates[max(array_intersect(array_keys($rebates),range(0,$items)))];

这个想法基本上是为了获得介于max0之间的最高密钥($items)。

答案 1 :(得分:5)

我认为上述单行解决方案并不优雅或可读。那么为什么不使用乍一看才能真正理解的东西呢?

$items = NUM_OF_ITEMS;
$rabate = 0;
foreach ($rabates as $rItems => $rRabate) {
    if ($rItems > $items) break;
    $rabate = $rRabate;
}

这显然需要一个排序数组,但至少在你的例子中给出了这个;)

好的,我知道,你不希望解决方案采用简单的循环。但是这个怎么样:

while (!isset($rabates[$items])) {
    --$items;
}
$rabate = $rabates[$items];

还是很简单,但有点短。我们能做得更短吗?

for (; !isset($rabates[$items]); --$items);
$rabate = $rabates[$items];

我们已经接近一条线了。所以,让我们做一些作弊:

for (; !isset($rabates[$items]) || 0 > $rabate = $rabates[$items]; --$items);

这比其他答案中的所有方法都短。它只有一个缺点:它会更改您稍后可能仍需要的$items的值。所以我们可以这样做:

for ($i = $items; !isset($rabates[$i]) || 0 > $rabate = $rabates[$i]; --$i);

这又是一个字符,我们保留$items

虽然我认为最后两个版本已经过于hacky了。最好坚持使用这个,因为它既简短又易懂:

for ($i = $items; !isset($rabates[$i]); --$i);
$rabate = $rabates[$i];

答案 2 :(得分:2)

这可能无需更改折扣数组。

但是必须以另一种方式构造数组才能使其工作

$rebates = array(
   3 => 0,      //Every number below this will get this rebate
   5 => 10,
   10 => 25,
  1000 => 35);  //Arbitrary large numer to catch all

$count = $_REQUEST["count"];

$rv = $rebates[array_shift(array_filter(array_keys($rebates), function ($v) {global $count; return $v > $count;}))];

echo $rv;

使用测试用例,只需更改网址中的计数

http://empirium.dnet.nu/arraytest.php?count=5
http://empirium.dnet.nu/arraytest.php?count=10

答案 3 :(得分:1)

目前为止我能管理得最好:

$testValue = 7;
array_walk( $rebates, function($value, $key, &$test) { if ($key > $test[0]) unset($test[1][$key]); } array($testValue,&$rebates) );

使用引用传递的令人讨厌的小怪癖,并剥离$ rebates数组中的任何条目,其中键在数字上大于$ testValue ...不幸的是,它仍然留下了较低键的条目,所以array_pop()需要获得正确的价值。请注意,它会主动减少原始$ rebates数组中的条目。

也许有人可以在此基础上放弃数组中较低的条目。

目前没有可用的5.3.3,所以没有使用匿名函数进行测试,但在使用标准回调函数时有效(尽可能多)。

修改

以我之前的单行为基础,添加第二行(所以可能不应该计算):

$testValue = 7;
array_walk( $rebates, function($value, $key, &$test) { if ($key > $test[0]) unset($test[1][$key]); } array($testValue,&$rebates) );
array_walk( array_reverse($rebates,true), function($value, $key, &$test) { if ($key < $test[0]) unset($test[1][$key]); } array(array_pop(array_keys($rebates)),&$rebates) );

现在导致$ rebates数组只包含一个元素,是原始$ rebates数组中比$ testValue更低的键的最高断点键。