(см версию последовательности задачи вместе с ленивой решения в моем втором обновлении до этого ответа ниже.)
(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])))))
Update:
Для расширения замечаний, полученных от выше , straighforward обобщение первой версии является следующее:
(defn sum-of-larger-squares [n & xs]
(apply + (map square (take n (reverse (sort xs))))))
Вторая версия прямолинейно обобщающий версии Артур писал в то же время:
(defn sum-of-larger-squares [n & xs]
(apply + (map square (drop n (sort xs)))))
Кроме того, я видел точно такая же проблема, решаемая в схеме, возможно, даже на SO ... Она включала в себя некоторые забавные решения, как тот, который вычислил некоторые из всех трех квадратов, затем вычитал наименьший квадрат (это очень просто выразить с помощью примитивов Схемы). Это «неэффективно», потому что он вычисляет один дополнительный квадрат, но он, безусловно, очень читабельен. Кажется, не удается найти ссылку сейчас, к сожалению.
Update 2:
В ответ на комментарий Артура Ulfeldt по вопросу, в ленивым решения (надеюсь забавной) другой версии проблемы. Код первое объяснение ниже:
(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))))
clojure.contrib.seq-utils
(или c.c.seq
) Lib есть для функции reductions
. Вместо этого можно использовать iterate
, но не без какой-либо дополнительной сложности (если только вы не захотите рассчитать длину seq чисел, которые должны быть обработаны в начале, что будет противоречить цели, которая может быть как можно более ленивой).
Объяснение с примером использования:
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)
Как правило, (moving-sum-of-smaller-squares pred n & nums)
генерирует ленивым SEQ сумм квадратов n
ПРЕД-наименьшим числом в более длинных начальных фрагментов исходной последовательности SEQ чисел, где «PRED «самый малый» означает наименьший по отношению к упорядочению, вызванному предикатом pred
. С pred
= >
рассчитывается сумма n
наибольших квадратов.
Эта функция использует трюк, упомянутый выше, при описании решения схемы, который суммировал три квадрата, затем вычитал наименьший из них, и поэтому он может корректировать текущую сумму на правильную сумму, не пересчитывая ее на каждом шаге.
С другой стороны, он выполняет большую сортировку; Я считаю, что не стоит пытаться оптимизировать эту часть, так как сортировка seqs всегда равна n
элементам, и на каждом шаге выполняется не более одной операции сортировки (нет, если сумма не требует настройки).
Может ли кто-нибудь найти ленивое решение? Мне бы это понравилось. Мне пришлось бы как-то обойти этот вид. –
У вас не может быть ленивого решения проблемы, которая по своей сути требует оценки всех входных данных, таких как сбор меньших двух три заданных числа. Однако ваш вопрос вдохновил меня на то, чтобы придумать слегка измененную версию проблемы - см. Мой ответ ниже для измененной проблемы и решения. –