2012-07-20 16 views
9

Często potrzebuję pewnego rodzaju rozszerzonego reduce, kiedy muszę przetworzyć przedmiot na czas (jak zmniejszyć), zebrać jakiś wynik (np. Zmniejszyć), ale zrobić proces oparty na poprzedni element sekwencji (w przeciwieństwie do zmniejszenia).Clojure: redukuj z trzema parametrami

Na przykład (głupawy), dodaj 1 do akumulatora, jeśli zarówno bieżący element, jak i poprzedni, są równe i odejmują jeden z nich są nieparzyste. To tylko głupi przypadek, ale często napotykam na tego rodzaju problemy. Generalnie robię wektor jako akumulator, tak, że pierwszy element jest rzeczywistą agregacją, a drugi jest poprzednim elementem. To nie jest zbyt eleganckie i z pewnością pełne gadatliwości.

Czy istnieje podstawowa funkcja, która może pomóc w takich przypadkach? Jaki jest najbardziej idiomatyczny sposób radzenia sobie z takim problemem? Dzięki

+0

proszę napisać przykład taki jak ten. input: xxx output: yyy – blueiur

Odpowiedz

15

partition na ratunek.

(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)) 

Albo trochę bardziej zwięzły:

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

"State" to tylko jedna "partycja" w Clojure. – ponzao

10

Dla tego konkretnego problemu, polecam kotarak na rozwiązanie, używając partycji śledzić poprzednie elementy. Ale w ogólnym przypadku, gdy musisz zarządzać jakimś stanem oprócz ostatecznej "odpowiedzi" Twojego reduku, możesz po prostu zmniejszyć na parę, mapę lub cokolwiek, a na końcu wyjść z wartości akumulatora. Na przykład:

(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))))