2010-10-27 12 views
12

He una matriz que refleja los porcentajes de descuentos en función del número de artículos pedidos:Escoger el valor más cercano a partir de una serie de superficies reflectantes rangos

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

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

¿Hay un elegante, forma de una línea para obtener el porcentaje de reembolso correcto para un número arbitrario 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 otorgar la respuesta aceptada una recompensa de 200, pero al parecer, tengo que esperar 24 horas hasta que pueda hacerlo. La pregunta está resuelta.

+3

sabes que es inútil pedir una sola línea cuando usted no especificar la línea de longitud máxima;) – Gordon

+0

llaves no están en un patrón? Por lo tanto, no podemos hacer una función – nerkn

+0

@Gordon: In code golf antes. – BoltClock

Respuesta

16

Aquí hay otro, de nuevo, no corto en absoluto.

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

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

+0

+1 ordenada y práctica –

+0

La estoy aceptando porque funciona de manera no destructiva, es el enfoque más corto, y no necesita cambios globales/cierres. ¡Gracias! –

+0

+1 relativamente corto y funcional – Thariama

1

¡No existe tal función central!

1

mejor que puedo manejar hasta el momento:

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

Utiliza un poco desagradable peculiaridad de pasar por referencia, y se despoja de cualquier entrada en el array $ rebajas donde la clave es numéricamente mayor que $ TestValue ... desafortunadamente, todavía deja entradas de clave más baja, por lo que se necesitaría 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 basarse en 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 devolución de llamada estándar.

EDITAR

Sobre la base de mi anterior de una sola línea, la adición de una segunda línea (así que 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 Resultados en el array $ rebajas que contiene sólo un único elemento, siendo la clave de punto de corte más alta de la matriz original de $ rebates que es una clave inferior a $ testValue.

+0

+1 ¡Un enfoque interesante! –

2

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

Pero la matriz debe ser construido 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; 

caso_prueba de trabajo, simplemente cambio de cómputo en url

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

+0

Muy bien, gracias. Estoy aceptando el enfoque de @ salathe porque es un poco más corto y funciona sin un cierre global, pero esto funcionará bien también. –

+0

De causa, su solución es más elegante :-) –

5

Creo que las soluciones de una línea anteriores no son realmente elegantes o 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; 
} 

Esto, obviamente, necesita un arreglo ordenado, pero al menos en su ejemplo esto se da;)

bien, sé, que no quieren la solución con el bucle simple. Pero ¿qué pasa con 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 estamos cerca de 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. Por lo que podríamos hacer:

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

Eso es otra vez un carácter menos $items y seguimos.

Aunque creo que las dos últimas versiones ya son demasiado hacky. Mejor seguir con éste, ya que es a la vez corto y comprensible:

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