针对Clojure实现问题的不同解决方案

Aru*_*n R 5 clojure

这是一个问题声明:

定义一个过程,该过程将三个数字作为参数,并返回两个较大数字的平方和.

解决方案很长,

(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))))
Run Code Online (Sandbox Code Playgroud)

只是想知道在Clojure中可以解决这个问题的不同/简洁方法.

Bri*_*per 8

(defn foo [& xs]
  (let [big-xs (take 2 (sort-by - xs))]
    (reduce + (map * big-xs big-xs))))
Run Code Online (Sandbox Code Playgroud)


Art*_*ldt 7

; 为什么只有3?N怎么样

(defn sum-of-squares [& nums]  
  (reduce + (map #(* % %) (drop 1 (sort nums)))))
Run Code Online (Sandbox Code Playgroud)

或者如果你想要"最大两个数字的总和:

(defn sum-of-squares [& nums]  
  (reduce + (map #(* % %) (take 2 (reverse (sort nums))))))
Run Code Online (Sandbox Code Playgroud)

(从2MichałMarczyk的回答中取2(逆转(排序))).


Mic*_*zyk 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])))))
Run Code Online (Sandbox Code Playgroud)

更新:

为了扩展上面的评论,第一个版本的直接概括是:

(defn sum-of-larger-squares [n & xs]
  (apply + (map square (take n (reverse (sort xs))))))
Run Code Online (Sandbox Code Playgroud)

第二个版本直接概括为亚瑟同时发布的版本:

(defn sum-of-larger-squares [n & xs]
  (apply + (map square (drop n (sort xs)))))
Run Code Online (Sandbox Code Playgroud)

另外,我已经看到在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))))
Run Code Online (Sandbox Code Playgroud)

(clojure.contrib.seq-utilsc.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)
Run Code Online (Sandbox Code Playgroud)

通常,在原始数字 seq 的越来越长的初始片段中(moving-sum-of-smaller-squares pred n & nums)生成 pred-smallest 数字的平方和的惰性 seq n,其中 'pred-smallest' 表示关于谓词引起的排序的最小pred。使用pred= ,计算最大平方>和。n

该函数使用了我上面描述的方案解决方案时提到的技巧,该方案将三个平方相加,然后减去最小的一个,因此能够按正确的量调整运行总和,而无需在每一步重新计算。

另一方面,它确实执行了大量的排序工作;我发现尝试和优化这一部分并不值得,因为被排序的 seq 总是n元素长,并且每一步最多有一个排序操作(如果总和不需要调整,则没有)。