Clojure 从集合中删除匹配元素的n个实例

Clojure 从集合中删除匹配元素的n个实例,clojure,Clojure,从集合1中删除集合2的匹配元素的n个实例的最佳方法是什么 (let [coll-1 [8 2] coll-2 [8 8 8 2] 以下是我第一次想到的解决原始问题的方法: ... ;; (remove (set coll-1) coll-2)) ;; --> () 但我意识到我必须做到: ... ;; (some-magic coll-1 coll-2)) ;; --> (8 8) 澄清: (some-magic {8 2} [8 8

从集合1中删除集合2的匹配元素的n个实例的最佳方法是什么

(let [coll-1 [8 2]
      coll-2 [8 8 8 2]
以下是我第一次想到的解决原始问题的方法:

   ...
;; (remove (set coll-1) coll-2))
;;     --> ()
但我意识到我必须做到:

   ...
;; (some-magic coll-1 coll-2))
;;     --> (8 8)
澄清:

 (some-magic {8 2} [8 8 8 2]) ;;Removes 1x8 and 1x2 from vector.
 (some-magic {8 8 2} [8 8 8 2]) ;;Removes 2x8 and 1x2 from vector.
编辑:


保持顺序是需要的。

我没有看到任何内置的序列操作函数能够很好地解决这个问题,尽管straitforward循环可以很好地构建结果:

user> (loop [coll-1 (set coll-1) coll-2 coll-2 result []]
        (if-let [[f & r] coll-2]
          (if (coll-1 f)
            (recur (disj coll-1 f) r result)
            (recur coll-1 r (conj result f)))
          result))
[8 8] 

下面是一个惰性解决方案,以
distinct
的风格编写:

(defn some-magic [count-map coll]
  (let [step (fn step [xs count-map]
               (lazy-seq
                 ((fn [[f :as xs] count-map]
                    (when-let [s (seq xs)]
                      (if (pos? (get count-map f 0))
                        (recur (rest s) (update-in count-map [f] dec))
                        (cons f (step (rest s) count-map)))))
                   xs count-map)))]
    (step coll count-map)))
第一个参数需要是一个映射,指示要删除的每个值的数量:

(some-magic {8 1, 2 1} [8 8 8 2]) ;; Removes 1x8 and 1x2 
;=> (8 8)

(some-magic {8 2, 2 1} [8 8 8 2]) ;; Removes 2x8 and 1x2
;=> (8)
下面是一个处理虚假值和无限输入的示例:

(take 10 (some-magic {3 4, 2 2, nil 1} (concat [3 nil 3 false nil 3 2] (range))))
;=> (false nil 0 1 4 5 6 7 8 9)

你想维持秩序吗?是的,这对我的目标是最好的。实现第一个目标,然后重新安排它将是第二个选择。您正在从
coll-2
中删除
coll-1
s,而不是相反。当然最好说
(一些神奇的{8 2}[8 8 8 2])
——换句话说,将删除指定为模仿multiset/bag的映射。要删除一组值的第一个实例吗?还是前n个实例?(映射有用时,映射值指示每个键要删除的实例数。)Mike:n是实例数,即{8}需要删除两个8,{8}是一个。