Ответ 1
Здесь еще один, опять же не короткий.
$percent = $rebates[max(array_intersect(array_keys($rebates),range(0,$items)))];
Идея состоит в том, чтобы получить максимальный ключ (max
), который находится где-то между 0
и $items
.
У меня есть массив, который отражает процентные скидки в зависимости от количества упорядоченных элементов:
$rebates = array(
1 => 0,
3 => 10,
5 => 25,
10 => 35)
означает, что для одного или двух элементов вы не получаете скидку; для 3+ предметов вы получаете 10%, для 5+ предметов 20%, для 10+ 35% и т.д.
Есть ли элегантный, однострочный способ получить правильный процент скидки для произвольного количества элементов, например 7
?
Очевидно, это можно решить, используя простой цикл: это не то, что я ищу. Меня интересует, есть ли основной массив или другая функция, о которой я не знаю, что может сделать это более элегантно.
Я собираюсь присудить принятый ответ на награду в 200, но, судя по всему, мне нужно подождать 24 часа, пока я не смогу это сделать. Вопрос решен.
Здесь еще один, опять же не короткий.
$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];
Это может работать без изменения массива.
Но массив должен быть построен по-другому, чтобы это работало
$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
Нет такой основной функции!
Лучшее, что я могу сделать до сих пор:
$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.