2010-05-11 11 views
6

Me gustaría obtener el elemento más pequeño de un vector. Para esto yo uso combinar las funciones reduce y min. Sin embargo, al proporcionar mi propia implementación de min consigo resultados inesperados:Resultado inesperado de la función de reducción

user=> (reduce (fn [x y] (< x y) x y) [1 2 3 2 1 0 1 2]) 
2 
user=> (reduce min [1 2 3 2 1 0 1 2 3]) 
0 

La reducir con el estándar min devuelve 0 como se esperaba. Sin embargo, cuando proporciono mi propia implementación, devuelve 2. ¿Qué estoy haciendo mal?

Respuesta

8

Te estás perdiendo un if:

(reduce (fn [x y] (if (< x y) x y)) ...) 
        ^-- note the if 

funciona bien. :-)

-1

Un fn usado con reducir probablemente necesite manejar 3 argumentos arios - 0, 1 y 2.

+1

realmente. La implementación de 'min' proporciona un ejemplo de 'reducir' que se usa con una función que no tiene una implementación nullary en Clojure. Además, el caso unario nunca es usado por Clojure's 'reduce'; una secuencia de longitud 1 siempre se reduce a su único elemento. En definitiva, necesitas un caso nulary si vas a tratar con secuencias vacías (si estás dispuesto a tratarlas como una entrada errónea, puedes prescindir de ellas) y definitivamente necesitas un caso binario (si nunca vas a hacerlo) tratar con secuencias de longitud> 1, no tiene sentido usar 'reducir' de todos modos). –

+0

@Michal, ah tienes toda la razón. 0 y 2 argumentos. – dnolen

5

Te has perdido if sobre el cuerpo de la función. Lo que sucede ahora es:

user> (use 'clojure.contrib.trace) 
nil 
user> (defn foo [x y] (< x y) x y) 
#'user/foo 
user> (dotrace [foo] (reduce foo [1 2 3 2 1 0 1 2])) 
TRACE t2229: (foo 1 2) 
TRACE t2229: => 2 
TRACE t2230: (foo 2 3) 
TRACE t2230: => 3 
TRACE t2231: (foo 3 2) 
TRACE t2231: => 2 
TRACE t2232: (foo 2 1) 
TRACE t2232: => 1 
TRACE t2233: (foo 1 0) 
TRACE t2233: => 0 
TRACE t2234: (foo 0 1) 
TRACE t2234: => 1 
TRACE t2235: (foo 1 2) 
TRACE t2235: => 2 
2 

En otras palabras, la función se pasa en devuelve siempre y, por lo se devuelve en la última iteración 2, ya que 2 es el último número de la secuencia usted redujo.

También tenga en cuenta que ya min se basa en reduce:

(defn min 
    "Returns the least of the nums." 
    ([x] x) 
    ([x y] (if (< x y) x y)) 
    ([x y & more] 
    (reduce min (min x y) more))) 
No
Cuestiones relacionadas