2010-03-01 6 views
7

Supongamos que tengo una matriz de valores [a, b, c, d, ...] y una función f (x, ...) que devuelve verdadero o falso.Mejor enfoque funcional para Y a través de una lista

[1,2,3,4].map {|x| f(x)} => [true true false true] 

En primer lugar, ¿cuál es la mejor manera de contraer la lista resultante en un valor verdadero o falso (a través de Y)? ¿Hay una función que me permita Mapa:

[true true false true] 

a:

((true && true) && false) && true 

utilizando una aplicación de pares acumulada del binario & & operador?

En este caso, el costo de evaluar la función es sustancial, por lo que me gustaría usar un estilo lisp "y" para evaluar los argumentos (aplicaciones de función) secuencialmente hasta que uno de ellos sea falso. Determinado que podría hacer:

!![1,2,3,4].each {|x| break false if !f(x) } 

Cuál es ugly. Esperando que haya una manera más elegante de hacer esto. Soy consciente de que podría agregar una nueva comprensión a Array, pero con la esperanza de que haya algo incorporado que lo haga mejor. Gracias

Respuesta

12

Está buscando Enumerable#all?, que devuelve verdadero si todas las invocaciones de su bloque son verdaderas. También hay Enumerable#any?, que devuelve verdadero si cualquiera de las invocaciones de su bloque son Truthy:

#!/usr/bin/ruby1.8 

def even(n) 
    n % 2 == 0 
end 

p [1, 2, 3, 4].all? { |i| even(i) } # => false 
p [2, 4, 6, 8].all? { |i| even(i) } # => true 
p [1, 2, 3, 4].any? { |i| even(i) } # => true 
p [1, 3, 5, 7].any? { |i| even(i) } # => false 

any? cortos curcuits: el primer valor Truthy hace que se devuelva true. Lo mismo ocurre con el cortocircuito all?: el primer valor falso hace que devuelva falso.

+0

Perdón por nitpicking, pero 'Fixnum' ya tiene métodos' even? 'Y' odd? '...;) –

+0

@Mladen Jablanovic, Buen punto. Para este ejemplo, quería una función definida por el usuario. –

1

¿Qué tal: [true, true, false, true].all?

Esto devolverá verdadero si la matriz no contiene nada que se evalúa como falsa o nula.

3

usted podría intentar plegar la matriz:

[true,true,false,true].inject(:&) #=> false (AND-ed) 
[true,true,false,true].inject(:|) #=> true (OR-ed) 
[1,2,3,4].inject(:+)    #=> 10 (summed) 
[1,2,3,4].inject(:*)    #=> 24 (multiplied) 

Usted consigue la idea. De nuevo a su ejemplo:

[1,2,3,4].map {|x| f(x) }.inject(:&) 

Sin embargo, no habrá un corto circuito - es probable que mejor mira en "alguna?" o "¿todo?" excepto que su "f()" tiene efectos secundarios (como la modificación de un almacenamiento persistente).

+0

Gracias, ¡esto responde la primera pregunta! Wayne responde el segundo. –

Cuestiones relacionadas