Skip to content

Instantly share code, notes, and snippets.

@markwoodhall
Last active September 21, 2016 10:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markwoodhall/7b76adc715ac3f21e9bfe747678aee58 to your computer and use it in GitHub Desktop.
Save markwoodhall/7b76adc715ac3f21e9bfe747678aee58 to your computer and use it in GitHub Desktop.
(def contents [123 123 123 456 567 890 444 444 555])
(def track-out [123 890 444])
;; Expected output (123 123 456 567 444 555)
(flatten (remove (into #{} track-out) (map #(if (= (count %) 1) (first %) (rest %)) (partition-by identity contents))))
@tcoupland
Copy link

Recursion with some lazy seqs and a sprinkling of sets:

(defn filter-first
  [c r]
  (when-let [f (first c)]
    (if (r f)
      (lazy-seq
       (filter-first (rest c) (disj r f)))
      (cons f (lazy-seq
               (filter-first (rest c) r))))))

(filter-first contents (set track-out))

Have fun!

@markwoodhall
Copy link
Author

Nice! Thanks!

@hiredman
Copy link

(require '[clojure.core.async :as async])

(defn f [parallelism to-remove input]
  (let [in (async/chan parallelism)
        out1 (async/chan parallelism)
        dist (async/pub in #(mod (hash (second %)) parallelism))]
    (dotimes [i parallelism]
      (let [in (async/chan)]
        (async/sub dist i in)
        (async/go-loop [seen #{}]
          (when-let [[output item] (async/<! in)]
              (if (contains? seen item)
                (async/>! output item)
                (when (not (contains? to-remove item))
                  (async/>! output item)))
              (async/close! output)
              (recur (conj seen item))))))
    (async/go
      (doseq [item input
              :let [oc (async/chan 1)]]
        (async/>! in [oc item])
        (async/>! out1 oc))
      (async/close! in)
      (async/close! out1))
    (async/<!!
     (async/go-loop [accum []]
       (if-let [oc (async/<! out1)]
         (if-let [item (async/<! oc)]
           (recur (conj accum item))
           (recur accum))
         accum)))))

;;user=> (f 18 #{123 890 444} [123 123 123 456 567 890 444 444 555])
[123 123 456 567 444 555]
;;user=> 

@tcoupland
Copy link

That looks totally nuts! :)

How about a stateful transducer:

(defn filter-first
  [f]
  (fn [rf]
    (let [f-atom (atom f)]
      (fn 
        ([] 
         (reset! f-atom f)
         (rf))
        ([acc x]
         (let [remaining-f @f-atom]
           (if (and (remaining-f x)
                    (compare-and-set! f-atom remaining-f (disj remaining-f x)))
             acc
             (rf acc x))))
        ([acc] 
         (rf acc))))))

(transduce (filter-first (set track-out)) conj contents) => [123 123 456 567 444 555]
(into '() (filter-first (set track-out)) contents) => (555 444 567 456 123 123)
(async/pipeline 18 to (filter-first (set track-out)) from)

With this you can use the logic over all manner of things!

@markwoodhall
Copy link
Author

Another one, for reference.

(defn mask-remove-one
  [from to]
  (persistent!
    (loop [bads (set from)
           accu (transient [])
           goods to]
      (if (nil? goods)
        accu
        (let [val (first goods)]
          (cond
            (contains? bads val) (recur (disj bads val)
                                        accu
                                        (next goods))
            :else (recur bads (conj! accu val) (next goods))))))))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment