如何在Clojure中区分/减去两个列表

时间:2014-04-21 14:20:23

标签: algorithm clojure set

示例:

1 1 1 3 3 4 4 5 5 6  L1
1     3 3   4 5      L2
  1 1     4     5 6  Res

约束:

  1. 差异/减法被定义为" set"来自L1减去(∖)L2
  2. 的元素
  3. L2始终是L1
  4. 的子集(⊆)
  5. L1和L2中的元素可以有重复
  6. 元素是基元(int,string)和所有相同类型
  7. 由于(3),

    (clojure.set/difference)在这里没有帮助。

5 个答案:

答案 0 :(得分:8)

(defn diff [s1 s2]
  (mapcat
    (fn [[x n]] (repeat n x))
    (apply merge-with - (map frequencies [s1 s2]))))

例如,给定

(def L1  [1 1 1 3 3 4 4 5 5 6])
(def L2  [1     3 3   4 5 ])

然后

(diff L1 L2)
;(1 1 4 5 6)

答案 1 :(得分:1)

这是一种方法。 步骤进行:

1.Find the frequencies for each list
2.Diff the frequencies
3.Repeat each element for the remaining value of frequency.


(defn myminus [s1 s2]
  (let [g1 (frequencies s1)
        g2 (frequencies s2)
        m (merge-with - g1 g2)
        r (mapcat #(repeat (second %) (first %)) m)]
    r))

答案 2 :(得分:1)

如果输入按顺序排列,那么你可以懒惰地执行此操作

(defn sdiff 
  [[x & rx :as xs] [y & ry :as ys]]
  (lazy-seq 
    (cond
      (empty? xs) nil
      (empty? ys) xs
      :else (case (compare x y)
              -1 (cons x (sdiff rx ys))
               0 (sdiff rx ry)
              +1 (sdiff xs ry)))))

举个例子:

(def L1 [1 1 1 3 3 4 4 5 5 6])
(def L2 [1 3 3 4 5])
(sdiff L1 L2) ;=> (1 1 4 5 6)

不是斐波那契数的懒数序列。 (请注意,我们不需要约束#2 - Fibonacci数字中重复的1' s不会引起问题。)

(defn fibs [] (map first (iterate (fn [[c n]] [n (+ c n)]) [0 1])))

(take 20 (sdiff (range) (fibs)))
;=> (4 6 7 9 10 11 12 14 15 16 17 18 19 20 22 23 24 25 26 27)

答案 3 :(得分:0)

由于L2始终是L1的一个子集,因此您可以在两个列表上group-by,并且只发出密钥的次数,因为每个分组的计数之间存在差异。

(def L1 (list 1 1 1 3 3 4 4 5 5 6))
(def L2 (list 1     3 3   4 5    ))

(defn diff [l1 l2]
  (let [a (group-by identity l1)
        b (group-by identity l2)]
    (mapcat #(repeat
              (-
               (count (second %))
               (count (get b (key %))))
              (key %)) a)))


(diff L1 L2)
;;(1 1 4 5 6)

答案 4 :(得分:0)

(defn diff-subtract
"The diff-subtract is defined as the sum of elements from L1 minus L2"
[list1 list2]
(let [l1 (into {} (map #(vector (first %) %) (partition-by identity (sort list1))))
      l2 (into {} (map #(vector (first %) %) (partition-by identity (sort list2))))]
     (-> (map
          #(repeat (- (count (l1 %)) (count (l2 %))) %)
           (range 1 (inc (apply max (map first l1)))))
     flatten)))

(diff-subtract [1 1 1 3 3 4 4 5 5 6] [1 3 3 4 5]) => (1 1 4 5 6)