3

我实现了一个简单的解决方案来打印 N 深度的帕斯卡三角形,我将在下面介绍。我的问题是,可以通过哪些方式对其进行改进以使其更加惯用?我觉得有很多东西看起来过于冗长或尴尬,例如,这个if块感觉不自然:(if (zero? (+ a b)) 1 (+ a b)). 任何反馈表示赞赏,谢谢!

(defn add-row [cnt acc]
  (let [prev (last acc)]
    (loop [n 0 row []]
      (if (= n cnt)
        row
        (let [a (nth prev (- n 1) 0)
              b (nth prev n 0)]
          (recur (inc n) (conj row (if (zero? (+ a b)) 1 (+ a b)))))))))


(defn pascals-triangle [n]
  (loop [cnt 1 acc []]
    (if (> cnt n)
      acc
      (recur (inc cnt) (conj acc (add-row cnt acc))))))
4

3 回答 3

8
(defn pascal []
  (iterate (fn [row]
             (map +' `(0 ~@row) `(~@row 0)))
           [1]))

或者,如果您想要最大程度地简洁:

(defn pascal []
  (->> [1] (iterate #(map +' `(0 ~@%) `(~@% 0)))))

对此进行扩展:高阶函数的观点是查看您的原始定义并实现类似:“我实际上只是f在初始值上计算一个函数,然后再次调用f,然后f再次......” . 这是一种常见的模式,因此定义了一个函数来为您覆盖无聊的细节,让您只需指定f初始值。而且因为它返回一个惰性序列,所以您现在不必指定n:您可以推迟它,并使用完整的无限序列,以及您想要的任何终止条件。

例如,也许我不想要第一n行,我只想找到总和是完美平方的第一行。然后我就可以了(first (filter (comp perfect-square? sum) (pascal))),而不必担心n我需要预先选择多大的 (假设 和 的定义很明显perfect-square?sum

感谢fogus的改进:我需要使用+'而不仅仅是+这样它在过去时不会溢出Long/MAX_VALUE

于 2013-06-28T04:15:09.257 回答
5
(defn next-row [row]
  (concat [1] (map +' row (drop 1 row)) [1]))

(defn pascals-triangle [n]
  (take n  (iterate next-row '(1))))
于 2013-06-28T04:04:54.233 回答
1

不像其他人那么简洁,但这是我的:)

(defn A [] 
  (iterate 
    (comp (partial map (partial reduce +)) 
      (partial partition-all 2 1) (partial cons 0))
        [1]))
于 2013-06-28T05:15:49.573 回答