(Vea una versión de secuencia del problema junto con una solución perezoso en mi segunda actualización a esta respuesta a continuación.)
(defn square [n]
(* n n))
;; generalises easily to larger numbers of arguments
(defn sum-of-larger-squares [x y z]
(apply + (map square (take 2 (reverse (sort [x y z]))))))
;; shorter; generalises easily if you want
;; 'the sum of the squares of all numbers but n smallest'
(defn sum-of-larger-squares [x y z]
(apply + (map square (drop 1 (sort [x y z])))))
Actualización:
Para ampliar sobre los comentarios de la anterior , la generalización straighforward de la primera versión es a esto:
(defn sum-of-larger-squares [n & xs]
(apply + (map square (take n (reverse (sort xs))))))
la segunda versión generaliza rodeos Arthur a la versión publicada en el ínterin:
(defn sum-of-larger-squares [n & xs]
(apply + (map square (drop n (sort xs)))))
Además, he visto exactamente el mismo problema a resolver en el esquema, posiblemente incluso en SO ... Se incluyó algunas soluciones diversión, como una que calcula el alguna de los tres cuadrados, luego restó el cuadrado más pequeño (que es muy sencillo de expresar con las primitivas del Esquema). Eso es "ineficiente" ya que calcula el cuadrado adicional, pero es ciertamente muy legible. Parece que no puede encontrar el enlace ahora, desafortunadamente.
Actualización 2:
En respuesta al comentario de Arthur Ulfeldt sobre la cuestión, una solución perezosa a un (esperemos divertido) versión diferente del problema. Código en primer lugar, a continuación la explicación:
(use 'clojure.contrib.seq-utils) ; recently renamed to clojure.contrib.seq
(defn moving-sum-of-smaller-squares [pred n nums]
(map first
(reductions (fn [[current-sum [x :as current-xs]] y]
(if (pred y x)
(let [z (peek current-xs)]
[(+ current-sum (- (* z z)) (* y y))
(vec (sort-by identity pred (conj (pop current-xs) y)))])
[current-sum
current-xs]))
(let [initial-xs (vec (sort-by identity pred (take n nums)))
initial-sum (reduce + (map #(* % %) initial-xs))]
[initial-sum initial-xs])
(drop n nums))))
El clojure.contrib.seq-utils
(o c.c.seq
) lib está ahí para que la función reductions
. iterate
podría usarse en su lugar, pero no sin cierta complejidad añadida (a menos que uno esté dispuesto a calcular la longitud de la secuencia de números para procesar al comienzo, lo que estaría en desacuerdo con el objetivo de permanecer tan flojo como sea posible).
Explicación con ejemplo de uso:
user> (moving-sum-of-smaller-squares < 2 [9 3 2 1 0 5 3])
(90 13 5 1 1 1)
;; and to prove laziness...
user> (take 2 (moving-sum-of-smaller-squares < 2 (iterate inc 0)))
(1 1)
;; also, 'smaller' means pred-smaller here -- with
;; a different ordering, a different result is obtained
user> (take 10 (moving-sum-of-smaller-squares > 2 (iterate inc 0)))
(1 5 13 25 41 61 85 113 145 181)
Generalmente, (moving-sum-of-smaller-squares pred n & nums)
genera una SEC perezoso de sumas de cuadrados de los n
números Pred-más pequeños en fragmentos iniciales cada vez más largas de la SEC original de números, donde 'pred "más pequeño" significa el más pequeño con respecto a la ordenación inducida por el predicado pred
. Con pred
= >
, se calcula la suma de n
cuadrados más grandes.
Esta función utiliza el truco que mencioné anteriormente al describir la solución de Esquema que suma tres cuadrados, luego resta el más pequeño, y así puede ajustar la suma en curso por la cantidad correcta sin volver a calcularla en cada paso.
Por otro lado, realiza una gran cantidad de clasificación; Encuentro que realmente no vale la pena tratar de optimizar esta parte, ya que los elementos que se ordenan son siempre n
elementos largos y hay un máximo de una operación de clasificación en cada paso (ninguno si la suma no requiere ajuste).
¿Alguien puede encontrar una solución perezosa? Me encantaría. Tendría que solucionar el problema de alguna manera. –
No puede tener una solución perezosa a un problema que inherentemente requiere la evaluación de todos los datos de entrada, como elegir los dos más pequeños tres números dados lo hacen. Su pregunta me inspiró, sin embargo, para llegar a una versión ligeramente modificada del problema - vea mi respuesta a continuación para el problema modificado y una solución. –