Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure实现问题的不同解决方案_Clojure - Fatal编程技术网

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

Clojure实现问题的不同解决方案,clojure,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)

以下是一个问题陈述:

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

解决办法很长

(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))))
(定义大[x y]
(如果(>xy)xy))
(定义大尺寸-3[x y z]
(如果(>(大x y)z)(大x y)z))
(定义小[x y]
(如果(最大%(<最小%)[x y z]))
(德芬广场[a]
(*a)
)
(定义平方和[x y z]
(+(正方形(大-3xyz))(正方形(第二大xyz)))
我只是想知道在Clojure中解决这个问题有什么不同/简洁的方法。

(请参阅下面我对这个答案的第二次更新中的问题的顺序版本和惰性解决方案。)

更新:

为了扩展上述评论,第一个版本的严格概括如下:

(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)))))
而且,我也看到了完全相同的问题在Scheme中得到了解决,甚至可能是如此。。。它包含了一些有趣的解决方案,比如计算所有三个正方形中的一些,然后减去最小的正方形(用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
)库用于
缩减功能<可以使用code>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)
user>(移动较小平方和<2[9 3 2 1 0 5 3])
(90 13 5 1 1 1)
;; 为了证明懒惰。。。
用户>(取2(移动较小平方和<2(迭代inc0)))
(1 1)
;; 此外,“更小”在这里意味着pred更小——带有
;; 不同的排序,得到不同的结果
用户>(取10(移动较小平方和>2(迭代inc 0)))
(1 5 13 25 41 61 85 113 145 181)
通常,
(移动较小的平方和pred n&nums)
在原始数字序列的越来越长的初始片段中生成
n
pred最小数字的平方和的延迟序列,其中“pred minimate”表示谓词
pred
诱导的顺序最小。使用
pred
=
,计算
n
最大平方和

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


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

;为什么只有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))))))

(从MichałMarczyk的答案中取2(反向(排序nums))。

在求和之前需要对每个数字进行平方运算。可以将+替换为#(+(*%1%1)(*%2%2)),使其读起来更像(应用平方和…)我喜欢你对这个问题的概括:)是的,我一开始忘记了平方运算,但在大约15秒钟内就纠正了它……你很快就发现了这一点。:-)至于对参数求和和和平方的匿名函数,如果你对两个数进行平方运算就可以了,但不能与
reduce
一起使用。如果你想的话解决这个问题它不能,它确实可以很好地评估不同问题的解决方案;-“不能与reduce一起使用。“s/reduce/apply.:)可以与reduce一起使用,不能与apply一起使用,因为它有固定数量的arg。我发现我把上面的最后两句话弄糟了……我的意思是(1)在使用它解决
reduce
的原始问题时必须小心,不要为累加器提供初始值;(2)你不能用它来解决这个问题的一般化版本。那是因为它将继续平方累加器,从而解决一个完全不同的数值问题。感谢你让我自己更正:-)此外,
apply
对于固定的算术函数也很好,当然前提是参数的数量是正确的提供。有人能找到一个懒惰的解决方案吗?我很乐意。我必须以某种方式绕过排序。对于一个本质上需要评估所有输入数据的问题,你不能有一个懒惰的解决方案,就像选择三个给定数字中较小的两个一样。然而,你的问题确实激发了我的灵感,让我想出一个稍微修改的版本关于这个问题——请参阅下面我的答案,了解修改后的问题和解决方案。我通常更喜欢应用reduce,因为它可以避免构建一个庞大的函数调用,并且可以保留惰性计算(尽管在本例中,(排序打破惰性)实际上,
(apply first[(iterate inc 0)]
(apply(fn[x&xs](iterate inc 0))
两者都产生0…对我来说似乎已经够懒了。:-)而且,
apply
用一个函数调用来代替
reduce
将要进行的多个函数调用。这并不是我不喜欢
reduce(defn foo [& xs]
  (let [big-xs (take 2 (sort-by - xs))]
    (reduce + (map * big-xs big-xs))))
(defn foo [& xs]
  (let [big-xs (take 2 (sort-by - xs))]
    (reduce + (map * big-xs big-xs))))