vector - operator - reduce in clojure
Clojure: ¿cómo agregar pares sucesivos en vector? (3)
Intentando escribir una función recursiva que agrega pares sucesivos en un vector.
[1 2 3 4] => [3 5 7]
Casi estancado y esto es lo que tengo actualmente:
(def tmp [ 1 2 3 4])
user> (map #(+ (second %) (first %)) (partition-all 2 tmp ))
Esto es incorrecto ya que agrega solo pares y no pares sucesivos. Obtengo [3 7]
lugar de [3 5 7]
Aquí hay otra posible solución:
(def tmp [1 2 3 4])
(map + tmp (rest tmp))
La partición toma un argumento adicional que especifica qué tan lejos avanzar entre cada partición.
(map #(apply + %) (partition 2 1 [1 2 3 4 5]))
=>
(3 5 7 9)
Usted está solicitando una función recursiva, y aunque en la mayoría de los casos las funciones de establecer y enumerar son preferibles antes de crear su propia función recursiva, esto no siempre es posible. Este problema también es muy fácil de escribir recursivamente de una manera funcional idiomática, usando un acumulador
La idea es que comiences con un acumulador vacío y construyas tu resultado paso a paso. El acumulador ( acc en este fragmento de código) contendrá la respuesta al final.
(defn add-pairs [v1]
(loop [the-list v1 acc []]
(if (next the-list) ;; checks wether there''s more than 1 left in the-list
(recur (rest the-list )
(conj acc (+ (first the-list) (second the-list))))
acc)))
¿Qué pasa aquí? Pasas el vector [1 2 3 4]
a v1
. Luego se inicia el ciclo y en él se inicializan dos variables:
the-list <- [1 2 3 4]
acc []
Simplemente la suma de los primeros dos elementos (+ (first the-list) (second the-list)
se agrega al acumulador. Luego, con recur
el ciclo se vuelve a llamar pasando el resto de la lista (rest the-list)
y el acumulador, que ahora tiene 3 (siendo la suma de los dos primeros elementos). Los nuevos valores son:
the-list <- [2 3 4]
acc [3]
próximos pasos :
the-list <- [3 4]
acc [3 5]
the-list <- [4]
acc [3 5 7]
Entonces la condición if ya no se cumple y se devuelve la cláusula else (convenientemente el acumulador, que ahora contiene la solución).
Idea general
Empiezas con un acumulador vacío y tu conjunto de entrada. Cada paso, el acumulador se acumula. En la mayoría de los casos, el conjunto de entrada es cada vez más pequeño en cada paso. Entonces se cumple alguna condición de si y el acumulador vuelve.
También muy clásico en este problema particular es que el conjunto de entrada está perdiendo su primer elemento en cada paso. (resto) es muy práctico aquí (cdr en la mayoría de los otros ceceos).
forma general
La forma loop / recurrir en clojure es muy buena, pero en muchos otros lenguajes, esta sintaxis es deficiente. Una solución muy clásica es tener dos funciones: una recursiva que hace el bucle, y otra con el mismo nombre, pero otra arity que hace la inicialización del acumulador. Más simple en el código de lo que es para explicar, así que aquí está en alguna sintaxis compuesta como java:
function add-pairs(v1 acc) {
if (cond)
//do stuff to v1 and acc
add-pairs(v1 acc)
else
return acc }
function add-pairs(v1) {
return add-pairs(v1,[])
}
var result = add-pairs([42 666 1447])