Skip to content

Instantly share code, notes, and snippets.

@ssboisen
Last active October 12, 2015 10:38
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 ssboisen/4014313 to your computer and use it in GitHub Desktop.
Save ssboisen/4014313 to your computer and use it in GitHub Desktop.
Hoffman encoding in Clojure
(defn branch? [node]
(= (:type node) :branch))
(defn get-chars [node]
(if (branch? node)
(:chars node)
[(:char node)]))
(defn leaf [char weight]
{:char char :weight weight :type :leaf})
(defn branch [left right]
{:left left :right right
:chars (sort (into (get-chars left) (get-chars right)))
:weight (+ (:weight left) (:weight right))
:type :branch})
(defn create-code-tree [text]
(letfn [(combine-trees [trees]
(let [[fst snd & r] trees]
(if (nil? snd)
trees
(recur (sort-by :weight (cons (branch fst snd) r))))))]
(first (combine-trees
(->> (frequencies text)
(sort-by second)
(map #(leaf (first %) (second %))))))))
(defn decode [tree bits]
(loop [_tree tree
bits bits
chars []]
(if (branch? _tree)
(let [bit (first bits)
v (if (= bit 0) :left :right)]
(recur (v _tree) (rest bits) chars))
(let [chars (into chars (get-chars _tree) )]
(if (empty? bits)
chars
(recur tree bits chars))))))
(defn encode [tree text]
(letfn [(has-char? [tree c]
(some #(= c %) (get-chars tree)))]
(loop [_tree tree
chars text
bits []]
(if (empty? chars)
bits
(if (branch? _tree)
(let [v (if (has-char? (:left _tree) (first chars)) :left :right)
bits (conj bits (if (= v :left) 0 1))]
(recur (v _tree) chars bits))
(recur tree (rest chars) bits))))))
(defn fast-encode [tree]
(let [code-map (into {} (map #(hash-map % (encode tree (str %))) (get-chars tree)))]
(fn [text] (reduce (fn [s c] (into s (get code-map c))) [] text))))
@mookid8000
Copy link

wtf?!

teach me!

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