在clojure中的所有子集

时间:2014-01-03 22:39:53

标签: clojure set subset combinatorics

我希望生成除空集

之外的集合的所有子集

(all-subsets #{1 2 3}) => #{#{1},#{2},#{3},#{1,2},#{2,3},#{3,1},#{1,2,3}}

如何在clojure中完成?

6 个答案:

答案 0 :(得分:11)

:dependencies project.clj中的[org.clojure/math.combinatorics "0.0.7"]

(require '[clojure.math.combinatorics :as combinatorics])

(->> #{1 2 3}
  (combinatorics/subsets)
  (remove empty?)
  (map set)
  (set))
;= #{#{1} #{2} #{3} #{1 2} #{1 3} #{2 3} #{1 2 3}}

在REPL:

clojure.math.combinatorics/subsets

{{1}}明智地返回一系列seqs,因此额外的转换可以匹配您想要的输出。

答案 1 :(得分:3)

@zcaudate:为了完整性,这是一个递归实现:

(defn subsets
  [s]
  (if (empty? s)
    #{#{}}
    (let [ts (subsets (rest s))]
      (->> ts
           (map #(conj % (first s)))
           (clojure.set/union ts)))))

;; (subsets #{1 2 3})

;; => #{#{} #{1} #{2} #{3} #{1 2} #{1 3} #{2 3} #{1 2 3}} (which is correct).

答案 2 :(得分:3)

这是一个简洁的尾递归版本,仅依赖于clojure.core。

(defn power [s]
   (loop [[f & r] (seq s) p '(())]
      (if f (recur r (concat p (map (partial cons f) p)))
            p)))

如果您希望将结果放在一组集中,请使用以下内容。

(defn power-set [s] (set (map set (power s))))

答案 3 :(得分:2)

这是@Brent M. Spell解决方案的一个细微变化,以寻求对惯用语Clojure中的表现考虑的启示。

我只是想知道是否在循环中构造子集而不是通过(map set ...)进行另一次迭代会节省一些开销,尤其是当集合非常大时?

(defn power [s]
    (set (loop [[f & r] (seq s) p '(#{})]
         (if f (recur r (concat p (map #(conj % f) p)))
             p))))

(power [1 2 3])
;; => #{#{} #{3} #{2} #{1} #{1 3 2} #{1 3} #{1 2} #{3 2}}

在我看来looprecur并不是懒惰的。 有一个懒惰的评估版本,如布伦特的,以保持表达优雅,同时使用懒惰同时实现效率将是很好的。

当有太多要计算的子集时,作为框架的这个版本具有另一个优点,即可以轻松支持子集候选者的修剪。可以在conj的位置添加修剪逻辑。我用它来实现“Frequent Item Set”的先前算法。

答案 4 :(得分:1)

请参阅:Algorithm to return all combinations of k elements from n



(defn comb [k l]
  (if (= 1 k) (map vector l)
      (apply concat
             (map-indexed
              #(map (fn [x] (conj x %2))
                    (comb (dec k) (drop (inc %1) l)))
              l))))


(defn all-subsets [s]
  (apply concat
         (for [x (range 1 (inc (count s)))]
           (map #(into #{} %) (comb x s)))))


(所有子集#{1 2 3})
; (#{1}#{2}#{3}#{1 2}#{1 3}#{2 3}#{1 2 3})

答案 5 :(得分:1)

此版本在ES5 version on Rosetta Code之后松散建模。我知道这个问题似乎已经合理地解决了......不管怎么说,你去吧。

(fn [s]
  (reduce 
    (fn [a b] (clojure.set/union a 
      (set (map (fn [y] (clojure.set/union #{b} y)) a))))
#{#{}} s))