+(defun mapappend (func seq)
+ (apply #'append (mapcar func seq)))
+
+(defun mapcar-append-string-nontailrec (func v)
+ "Concatenate results of mapcar lambda calls"
+ (aif (car v)
+ (concatenate 'string (funcall func it)
+ (mapcar-append-string-nontailrec func (cdr v)))
+ ""))
+
+
+(defun mapcar-append-string (func v &optional (accum ""))
+ "Concatenate results of mapcar lambda calls"
+ (aif (car v)
+ (mapcar-append-string
+ func
+ (cdr v)
+ (concatenate 'string accum (funcall func it)))
+ accum))
+
+(defun mapcar2-append-string-nontailrec (func la lb)
+ "Concatenate results of mapcar lambda call's over two lists"
+ (let ((a (car la))
+ (b (car lb)))
+ (if (and a b)
+ (concatenate 'string (funcall func a b)
+ (mapcar2-append-string-nontailrec func (cdr la) (cdr lb)))
+ "")))
+
+(defun mapcar2-append-string (func la lb &optional (accum ""))
+ "Concatenate results of mapcar lambda call's over two lists"
+ (let ((a (car la))
+ (b (car lb)))
+ (if (and a b)
+ (mapcar2-append-string func (cdr la) (cdr lb)
+ (concatenate 'string accum (funcall func a b)))
+ accum)))
+
+(defun append-sublists (list)
+ "Takes a list of lists and appends all sublists"
+ (let ((results (car list)))
+ (dolist (elem (cdr list) results)
+ (setq results (append results elem)))))
+
+
+;; alists and plists
+
+(defun alist-elem-p (elem)
+ (and (consp elem) (atom (car elem)) (atom (cdr elem))))
+
+(defun alistp (alist)
+ (when (listp alist)
+ (dolist (elem alist)
+ (unless (alist-elem-p elem)
+ (return-from alistp nil)))
+ t))
+
+(defmacro update-alist (akey value alist &key (test '#'eql) (key '#'identity))
+ "Macro to support below (setf get-alist)"
+ (let ((elem (gensym "ELEM-"))
+ (val (gensym "VAL-")))
+ `(let ((,elem (assoc ,akey ,alist :test ,test :key ,key))
+ (,val ,value))
+ (cond
+ (,elem
+ (setf (cdr ,elem) ,val))
+ (,alist
+ (setf (cdr (last ,alist)) (list (cons ,akey ,val))))
+ (t
+ (setf ,alist (list (cons ,akey ,val)))))
+ ,alist)))
+
+(defun get-alist (key alist &key (test #'eql))
+ (cdr (assoc key alist :test test)))
+
+(defun (setf get-alist) (value key alist &key (test #'eql))
+ "This won't work if the alist is NIL."
+ (update-alist key value alist :test test)
+ value)
+
+(defun alist-plist (alist)
+ (apply #'append (mapcar #'(lambda (x) (list (car x) (cdr x))) alist)))
+
+(defun plist-alist (plist)
+ (do ((alist '())
+ (pl plist (cddr pl)))
+ ((null pl) alist)
+ (setq alist (acons (car pl) (cadr pl) alist))))
+
+(defmacro update-plist (pkey value plist &key (test '#'eql))
+ "Macro to support below (setf get-alist)"
+ (let ((pos (gensym)))
+ `(let ((,pos (member ,pkey ,plist :test ,test)))
+ (if ,pos
+ (progn
+ (setf (cadr ,pos) ,value)
+ ,plist)
+ (setf ,plist (append ,plist (list ,pkey ,value)))))))
+
+
+(defun unique-slot-values (list slot &key (test 'eql))
+ (let ((uniq '()))
+ (dolist (item list (nreverse uniq))
+ (let ((value (slot-value item slot)))
+ (unless (find value uniq :test test)
+ (push value uniq))))))
+
+