Skip to content

Instantly share code, notes, and snippets.

@hindol
Last active March 13, 2020 11:27
Show Gist options
  • Save hindol/c92a768f7f784379dc8bcd546a60fa42 to your computer and use it in GitHub Desktop.
Save hindol/c92a768f7f784379dc8bcd546a60fa42 to your computer and use it in GitHub Desktop.
Bag / MultiSet in Clojure (How to create a custom collection in Clojure)
(ns com.github.hindol.euler.collections
(:import
(clojure.lang IPersistentCollection
IPersistentSet
Seqable)))
(deftype Bag [^clojure.lang.IPersistentMap m
^long n]
IPersistentSet
(get [this k]
(if (contains? m k) k nil))
(contains [this k]
(contains? m k))
(disjoin [this k]
(Bag. (if (= 1 (m k)) (dissoc m k) (update m k dec))
(dec n)))
IPersistentCollection
(count [this]
n)
(empty [this]
(Bag. (.empty m) 0))
(cons [this k]
(Bag. (assoc m k (inc (get m k 0)))
(inc n)))
(equiv [this o]
(and (isa? (class o) Bag)
(= n (.n ^Bag o))
(.equiv m (.m ^Bag o))))
Seqable
(seq [this] (mapcat repeat (vals m) (keys m))))
(defn bag
[& keys]
(Bag. (frequencies keys)
(count keys)))
; (coll/bag 1 2 2 3 3 3) => #{1 2 2 3 3 3}
; (conj (coll/bag 1 2 2 3 3 3) 4 4 4 4) => #{1 2 2 3 3 3 4 4 4 4}
; (disj (coll/bag 1 2 2 3 3 3) 3) => #{1 2 2 3 3}
@hindol
Copy link
Author

hindol commented Feb 23, 2020

Scaffold generated using this utility function: https://gist.github.com/semperos/3835392

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