Escogiendo el valor más cercano de una matriz que refleja rangos

Tengo una matriz que refleja los porcentajes de reembolso en función de la cantidad de artículos pedidos:

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

lo que significa que para uno o dos artículos, no obtienes ningún descuento; para más de 3 elementos obtienes 10%, para más de 5 elementos 20%, para 10+ 35% y así sucesivamente.

¿Existe una forma elegante y única de obtener el porcentaje de reembolso correcto para una cantidad arbitraria de artículos, digamos 7 ?

Obviamente, esto se puede resolver con un simple bucle: eso no es lo que estoy buscando. Me interesa si hay una matriz de núcleos u otra función que no conozco que pueda hacer esto de forma más elegante.

Voy a otorgarle a la respuesta aceptada una recompensa de 200, pero aparentemente, tengo que esperar 24 horas hasta que pueda hacer eso. La pregunta está resuelta.

Aquí hay otro, de nuevo no es para nada corto.

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

La idea es básicamente obtener la clave más alta ( max ) que está en algún lugar entre 0 y $items .

Creo que las soluciones de una línea anteriores no son realmente elegantes ni legibles. Entonces, ¿por qué no usar algo que realmente pueda ser entendido por alguien a primera vista?

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

Obviamente, esto necesita una matriz ordenada, pero al menos en su ejemplo esto se da;)

De acuerdo, lo sé, no quieres la solución con el simple bucle. Pero que hay de esto:

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

Aún bastante sencillo, pero un poco más corto. ¿Podemos hacer aún más corto?

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

Ya nos estamos acercando a una línea. Así que hagamos un poco de trampa:

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

Esto es más corto que todos los enfoques en otras respuestas. Tiene solo una desventaja: cambia el valor de $items que aún puede necesitar más adelante. Entonces podríamos hacer:

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

De nuevo, es un personaje menos y guardamos $items .

Aunque creo que las últimas dos versiones ya son demasiado extravagantes. Mejor quedarse con este, ya que es corto y comprensible:

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

Esto podría funcionar sin cambiar la matriz de reembolso.

Pero la matriz debe construirse de otra manera para que esto funcione

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

Testcase de trabajo, solo cambia el recuento en url

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

¡No hay tal función central!

Lo mejor que puedo manejar hasta ahora:

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

Utiliza una pequeña peculiaridad desagradable de pasar por referencia, y elimina cualquier entrada en la matriz de $ rebates donde la clave es numéricamente mayor que $ testValue … desafortunadamente, aún deja entradas de menor clave, por lo que sería necesario un array_pop () para obtener el valor correcto Tenga en cuenta que reduce activamente las entradas en la matriz original $ rebates.

Quizás alguien pueda construir sobre esto para descartar las entradas más bajas en la matriz.

No tiene a mano el 5.3.3 por el momento, por lo que no se prueba usando una función anónima, pero funciona (tanto como funciona) cuando se usa una función de callback estándar.

EDITAR

Sobre la base de mi anterior delineador, agregué una segunda línea (probablemente no debería contar):

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

Ahora da como resultado la matriz $ rebates que contiene solo un elemento, siendo la clave de punto de corte más alta de la matriz de reembolsos $ original que es una clave inferior a $ testValue.