(defun accumulate (xss) ;; Take a list of lists, and consolidate sublists with a common ;; first element. (if (<= (length xss) 1) xss (if (string-equal (caar xss) (caadr xss)) (accumulate (cons (cons (caar xss) (append (cdar xss) (cdadr xss))) (cddr xss))) (cons (car xss) (accumulate (cdr xss)))))) (defun anags (words) ;; Take a list of strings, and return a list of lists of strings ;; which are anagrams of each other. (let ((a (mapcar (lambda (x) (list (sort (copy-seq x) #'char-lessp) x)) words))) (mapcar #'rest (remove-if (lambda (x) (<= (length x) 2)) (accumulate (sort a #'string-lessp :key #'first)))))) (defun anags-file (filename) ;; Read a list of strings from named file, print sets of anagrams ;; on stdout. (with-open-file (in-stream filename :direction :input) (mapcar (lambda (x) (format t "~{~A ~}~&" x)) (anags (loop for line = (read-line in-stream nil) until (equal line nil) collect line)))) nil)