2012-07-20 22 views
9

A menudo necesito un tipo de expansión reduce cada vez que debo procesar un elemento en el momento (como reducir), acumulo algún tipo de resultado (como reducir) pero hago el proceso basado en el ítem anterior de la secuencia (a diferencia de reducir).Clojure: reducir con tres parámetros

Por ejemplo (una tontería), agregue 1 al acumulador si el artículo actual y el anterior son pares y resta uno de ellos son impares. Este es solo un caso estúpido, pero me he encontrado con este tipo de problemas a menudo. Generalmente hago un vector como acumulador, de modo que el primer elemento es la agregación real y el segundo es el elemento anterior. Esto no es muy elegante y ciertamente prolijo.

¿Existe alguna función básica para ayudar en esos casos? ¿Cuál es la forma más idiomática de lidiar con tal problema? Gracias

+0

por favor escriba un ejemplo como este. entrada: xxx salida: yyy – blueiur

Respuesta

15

partition al rescate.

(reduce (fn [i [a b]] 
      (cond 
      (and (even? a) (even? b)) (inc i) 
      (and (odd? a) (odd? b)) (dec i) 
      :else i)) 
     0 (partition 2 1 input)) 

O un poco más concisa:

(reduce (fn [i pair] 
      (condp every? pair 
      even? (inc i) 
      odd? (dec i) 
      i)) 
     0 (partition 2 1 input)) 
+2

"Estado" es solo una 'partición' en Clojure. – ponzao

10

Para este problema en particular, recomiendo de solución kotarak, utilizando partición para realizar un seguimiento de los elementos anteriores. Pero en el caso general, donde necesita administrar algún estado además de la eventual "respuesta" de su reductor, simplemente puede reducir más de un par, o un mapa o lo que sea, y al final obtener el valor del acumulador. Por ejemplo:

(defn parity [coll] 
    (first (reduce (fn [[acc prev] x] 
        [(cond (and (even? prev) (even? x)) (inc acc) 
          (and (odd? prev) (odd? x)) (dec acc) 
          :else acc) 
        x]) 
       [0 (first coll)], (rest coll))))