提问人:Pekka 提问时间:10/27/2010 最后编辑:Pekka 更新时间:3/28/2011 访问量:1644
从反映范围的数组中选取最接近的值
Picking the nearest value from an array reflecting ranges
问:
我有一个数组,它根据订购的商品数量反映回扣百分比:
$rebates = array(
1 => 0,
3 => 10,
5 => 25,
10 => 35)
这意味着对于一两件商品,您不会获得回扣;对于 3+ 项目,您将获得 10%,对于 5+ 项目,您将获得 20%,对于 10+ 35%,依此类推。
比如说,有没有一种优雅的单行方法可以为任意数量的商品获得正确的回扣百分比?7
显然,这可以使用一个简单的循环来解决:这不是我要找的。我感兴趣的是,是否有核心数组或其他我不知道的函数可以更优雅地做到这一点。
我将奖励接受的答案 200 的赏金,但显然,我必须等待 24 小时才能做到这一点。问题解决了。
答:
到目前为止,我能做到的最好的:
$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。
这可能在不更改返利数组的情况下起作用。
但是数组必须以另一种方式构造才能使其工作
$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;
工作测试用例,只需更改 url 中的计数
http://empirium.dnet.nu/arraytest.php?count=5 http://empirium.dnet.nu/arraytest.php?count=10
评论
这是另一个,同样一点也不短。
$percent = $rebates[max(array_intersect(array_keys($rebates),range(0,$items)))];
这个想法基本上是获得介于 和 之间的最高键 ()。max
0
$items
评论
我认为上面的单行解决方案并不是很优雅或可读。那么,为什么不使用一些乍一看就能真正理解的东西呢?
$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
虽然我认为最后两个版本已经太骇人听闻了。最好坚持这个,因为它既简短又易于理解:
for ($i = $items; !isset($rabates[$i]); --$i);
$rabate = $rabates[$i];
评论