Tail递归Clojure函数用于计算组合

时间:2014-03-17 11:29:38

标签: recursion clojure functional-programming tail-recursion

我有一个函数,给定一个向量,返回所有无序组合:

(defn combination [ps]
  (loop [acc []
         ps ps]
    (if (= 2 (count ps))
      (conj acc (apply vector ps))
      (recur (apply conj acc (map #(vector (first ps) %) (rest ps)))
             (rest ps)))))

这很好用,但对我来说似乎有点费解。

在Clojure中有没有更直接,惯用的方法来实现这一目标?我很高兴使用Clojure核心或库函数,因为这肯定是我对“惯用语”定义的一部分。 :)

3 个答案:

答案 0 :(得分:3)

Clojure有 clojure.math.combinatorics ,它包含许多方便的功能。所以可以说是"惯用的"你在Clojure做的事情的方法是导入/要求 clojure.math.combinatorics ,然后只需用 n = 2来调用组合。

...>  (comb/combinations [1 2 3 4] 2)
((1 2) (1 3) (1 4) (2 3) (2 4) (3 4))

为此,您需要先添加正确的依赖项。

在我写这篇文章时,最新版本为:[org.clojure/math.combinatorics "0.0.7"]

我确实需要它" :as comb":

(:require [clojure.math.combinatorics :as comb]

如果您不想使用 math.combinatorics ,您可以编辑问题以使其更加精确,我会删除我的答案。

答案 1 :(得分:1)

有些讽刺......

(defn combination [ps]
  (clojure.math.combinatorics/combinations ps 2))

......这是懒惰的,但the source code是你的两倍或三倍。

答案 2 :(得分:1)

您的代码会返回按顺序获取的两个元素的所有选择。另一种方法是......

(defn combination [s]
  (let [tails (take-while next (iterate rest s))]
    (mapcat (fn [[f & rs]] (map #(vector f %) rs)) tails)))

这比你的短,而且也很懒。但它可能会变慢。