需要一个类似于disj的功能,但需要一个clojure中的列表。它总体上可能吗?

时间:2012-11-28 13:07:34

标签: clojure

我需要遍历一个列表并对每个元素和排除该元素的元素进行一些计算。例如,拥有列表(1 2 3 1),我需要配对(1) (2 3 1)(2) (1 3 1)(3) (1 2 1)(1) (2 3 1)

3 个答案:

答案 0 :(得分:5)

  

(...)包含每个元素和除该元素之外的元素。

每个元素听起来都像map排除该元素听起来像filter。让我们从后者开始。

user=> (filter #(not= % 1) '(1 2 3))
(2 3)

大。现在让我们尝试将其映射到所有元素上。

user=> (let [coll '(1 2 3)] (map (fn [elem] (filter #(not= % elem) coll)) coll))
((2 3) (1 3) (1 2))

创建实际对是留给读者的练习。提示:修改map中使用的闭包。

请记住,上面建议的解决方案应该适用于短列表,但它的复杂度为O(n²)。另一个问题是没有正确处理带有重复项的集合。

让我们采取递归方法。我们将递归基于looprecur

(defn pairs [coll]
  (loop [ahead coll behind [] answer []]
    (if (empty? ahead)
      answer
      (let [[current & remaining] ahead]
        (recur remaining
               (conj behind current)
               (conj answer [(list current)
                             (concat behind remaining)]))))))

一个简单的例子:

user=> (pairs '(1 2 3))
[[(1) (2 3)] [(2) (1 3)] [(3) (1 2)]]

带有重复的矢量:

user=> (pairs [1 5 6 5])
[[(1) (5 6 5)] [(5) (1 6 5)] [(6) (1 5 5)] [(5) (1 5 6)]]

答案 1 :(得分:5)

似乎是列表理解的工作:

(defn gimme-pairs [coll]
  (for [x coll]
    [(list x) (remove #{x} coll)]))

user=> (gimme-pairs [1 2 3])
([(1) (2 3)] [(2) (1 3)] [(3) (1 2)])

我实际上会跳过为单个元素创建一个列表,这会使代码更容易:

(defn gimme-pairs [coll]
  (for [x coll]
    [x (remove #{x} coll)]))

user=> (gimme-pairs [1 2 3])
([1 (2 3)] [2 (1 3)] [3 (1 2)])

如果您需要保留重复项,则可以使用索引集合:

(defn gimme-pairs [coll]
  (let [indexed (map-indexed vector coll)
        remove-index (partial map second)]
    (for [[i x] indexed]
      [x (remove-index (remove #{[i x]} indexed))])))

user=> (gimme-pairs [1 2 3 1])
([1 (2 3 1)] [2 (1 3 1)] [3 (1 2 1)] [1 (1 2 3)])

答案 2 :(得分:1)

(def l [1 2 3])

(first (reduce (fn [[res ll] e]
                 [(conj res [(list e) (rest ll)])
                  (conj (vec (rest ll)) e)])
               [[] l] l))
=> [[(1) (2 3)] [(2) (3 1)] [(3) (1 2)]]