Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove n instances of matched elements from collection

Tags:

clojure

What is the best way to remove n instances of matched elements of collection-2 from collection-1?

(let [coll-1 [8 2]
      coll-2 [8 8 8 2]

Here's what I first came up with to solve original problem:

   ...
;; (remove (set coll-1) coll-2))
;;     --> ()

But realised I must achieve:

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

Clarification:

 (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.

Edit:

Preserving the order is desired.

like image 876
QuestionProgram Avatar asked Nov 24 '25 07:11

QuestionProgram


1 Answers

Here is a lazy solution, written in the style of 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)))

The first argument needs to be a map indicating how many of each value to remove:

(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)

Here is an example dealing with falsey values and infinite input:

(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)
like image 112
Mike Fikes Avatar answered Nov 26 '25 16:11

Mike Fikes