这是一个问题声明:
定义一个过程,该过程将三个数字作为参数,并返回两个较大数字的平方和。
解决方案很长,
(defn large [x y]
(if (> x y) x y))
(defn large-3 [x y z]
(if(> (large x y) z) (large x y) z))
(defn small [x y]
(if (< x y) x y))
(defn small-3 [x y z]
(if (< (small x y) z ) (small x y) z))
(defn second-largest [x y z]
(let [greatest (large-3 x y z)
smallest (small-3 x y z)]
(first (filter #(and (> greatest %) (< smallest %)) [x y z]))))
(defn square [a]
(* a a)
)
(defn sum-of-square [x y z]
(+ (square (large-3 x y z)) (square (second-largest x y z))))
只是想知道在Clojure中可以解决这个问题的不同/简洁方法。
答案 0 :(得分:8)
(defn foo [& xs]
(let [big-xs (take 2 (sort-by - xs))]
(reduce + (map * big-xs big-xs))))
答案 1 :(得分:7)
为什么只有3? N怎么样
(defn sum-of-squares [& nums]
(reduce + (map #(* % %) (drop 1 (sort nums)))))
或者如果你想要“最大的两个数字之和:
(defn sum-of-squares [& nums]
(reduce + (map #(* % %) (take 2 (reverse (sort nums))))))
(从2MichałMarczyk的回答中取2(反向(排序)))。
答案 2 :(得分:3)
(在下面的答案的第二次更新中,请参阅问题的序列版本以及一个懒惰的解决方案。)
(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])))))
更新
为了扩展上述评论,第一个版本的直接概括是:
(defn sum-of-larger-squares [n & xs]
(apply + (map square (take n (reverse (sort xs))))))
第二个版本直截了当地概括了Arthur在此期间发布的版本:
(defn sum-of-larger-squares [n & xs]
(apply + (map square (drop n (sort xs)))))
另外,我已经看到在Scheme中解决的问题完全相同,甚至可能在SO上...它包括一些有趣的解决方案,比如计算所有三个方块中的一些,然后减去最小的方块(这是非常的用Scheme原语直接表达)。这是“无效的”因为它计算了一个额外的正方形,但它肯定是非常可读的。不幸的是,现在似乎无法找到链接。
更新2:
回应Arthur 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
代替,但不能没有一些额外的复杂性(除非有人愿意计算在开始时要处理的数字序列的长度,这与保持懒惰的目标不一致尽可能)。
使用示例说明:
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-smallest'表示最小关于谓词pred
引起的排序。使用pred
= >
,计算n
最大正方形的总和。
这个函数在描述方案解决方案时使用了上面提到的技巧,它总结了三个方块,然后减去了最小的方格,因此能够将运行总和调整正确的数量而无需在每一步重新计算它。
另一方面,它确实执行了大量的排序;我发现尝试优化这个部分并不值得,因为被排序的seqs总是n
个元素长,并且每个步骤最多有一个排序操作(如果总和不需要调整,则没有)。