(defun lzw-compress (sequence elements)
(let ((dictionary (make-hash-table :test #'equalp))
(index -1)
(seq nil))
(map nil
(lambda (e)
(setf (gethash (list e) dictionary) (incf index)))
elements)
(nconc (loop
for e across sequence
do (setf seq (list* e seq))
unless (gethash seq dictionary)
collect (gethash (cdr seq) dictionary)
and
do (setf (gethash seq dictionary) (incf index)
seq (list (car seq))))
(list (gethash seq dictionary)))))
(defun lzw-decompress (list elements)
(let ((dictionary (make-array (length elements)
:adjustable t
:fill-pointer t
:initial-contents (map 'list #'list elements))))
(loop
for index in list
for ee = e
and e = (if (< index (length dictionary))
(aref dictionary index)
e)
for s = (append (last e) ee)
unless (find s dictionary :test #'equalp)
do (vector-push-extend s dictionary)
append (reverse (setf e (aref dictionary index))))))
(defun test (data &optional elements)
(let* ((data-elements (or elements (remove-duplicates data)))
(compressed (lzw-compress data data-elements))
(decompressed (lzw-decompress compressed data-elements)))
(format t "~%characters: ~s~%uncompressed: ~a~%compressed: ~a~%decompressed: ~{~a~}~%"
data-elements data compressed decompressed)
nil))
(test "010101010" "0123")
(test "01230123012" "0123")
(test "00001110000" "0123")
(test "akamakigami aomakigami kimakigami")