;;;; Programmer: Kevin M. Rosenberg
;;;; Date Started: Apr 2000
;;;;
-;;;; $Id: lists.lisp,v 1.10 2003/08/12 06:37:53 kevin Exp $
-;;;;
;;;; This file, part of KMRCL, is Copyright (c) 2002 by Kevin M. Rosenberg
;;;;
;;;; KMRCL users are granted the rights to distribute and use this software
(unless (find elem l1)
(setq l1 (append l1 (list elem))))))
-(defun remove-from-tree-if (pred tree)
+(defun remove-from-tree-if (pred tree &optional atom-processor)
"Strip from tree of atoms that satistify predicate"
(if (atom tree)
(unless (funcall pred tree)
- tree)
- (let ((car-strip (remove-from-tree-if pred (car tree)))
- (cdr-strip (remove-from-tree-if pred (cdr tree))))
+ (if atom-processor
+ (funcall atom-processor tree)
+ tree))
+ (let ((car-strip (remove-from-tree-if pred (car tree) atom-processor))
+ (cdr-strip (remove-from-tree-if pred (cdr tree) atom-processor)))
(cond
((and car-strip (atom (cadr tree)) (null cdr-strip))
- (list car-strip))
+ (list car-strip))
((and car-strip cdr-strip)
- (cons car-strip cdr-strip))
+ (cons car-strip cdr-strip))
(car-strip
- car-strip)
+ car-strip)
(cdr-strip
- cdr-strip)))))
+ cdr-strip)))))
(defun find-tree (sym tree)
"Finds an atom as a car in tree and returns cdr tree at that positions"
(if (or (null tree) (atom tree))
nil
(if (eql sym (car tree))
- (cdr tree)
+ (cdr tree)
(aif (find-tree sym (car tree))
- it
- (aif (find-tree sym (cdr tree))
- it
- nil)))))
-
-(defun flatten (lis)
- (cond ((atom lis) lis)
- ((listp (car lis))
- (append (flatten (car lis)) (flatten (cdr lis))))
- (t (append (list (car lis)) (flatten (cdr lis))))))
+ it
+ (aif (find-tree sym (cdr tree))
+ it
+ nil)))))
+
+(defun flatten (tree)
+ (let ((result '()))
+ (labels ((scan (item)
+ (if (consp item)
+ (map nil #'scan item)
+ (push item result))))
+ (scan tree))
+ (nreverse result)))
;;; Keyword functions
+;; ECL doesn't allow FOR clauses after UNTIL.
+#-ecl
(defun remove-keyword (key arglist)
(loop for sublist = arglist then rest until (null sublist)
- for (elt arg . rest) = sublist
- unless (eq key elt) append (list elt arg)))
+ for (elt arg . rest) = sublist
+ unless (eq key elt) append (list elt arg)))
(defun remove-keywords (key-names args)
(loop for ( name val ) on args by #'cddr
- unless (member (symbol-name name) key-names
- :key #'symbol-name :test 'equal)
- append (list name val)))
+ unless (member (symbol-name name) key-names
+ :key #'symbol-name :test 'equal)
+ append (list name val)))
(defun mapappend (func seq)
(apply #'append (mapcar func seq)))
(defun mapcar-append-string-nontailrec (func v)
- "Concatenate results of mapcar lambda calls"
+ "Concatenate results of mapcar lambda calls"
(aif (car v)
(concatenate 'string (funcall func it)
- (mapcar-append-string-nontailrec func (cdr v)))
+ (mapcar-append-string-nontailrec func (cdr v)))
""))
(defun mapcar-append-string (func v &optional (accum ""))
- "Concatenate results of mapcar lambda calls"
+ "Concatenate results of mapcar lambda calls"
(aif (car v)
- (mapcar-append-string
- func
- (cdr v)
- (concatenate 'string accum (funcall func it)))
+ (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"
+ "Concatenate results of mapcar lambda call's over two lists"
(let ((a (car la))
- (b (car lb)))
+ (b (car lb)))
(if (and a b)
(concatenate 'string (funcall func a b)
- (mapcar2-append-string-nontailrec func (cdr la) (cdr lb)))
+ (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"
+ "Concatenate results of mapcar lambda call's over two lists"
(let ((a (car la))
- (b (car lb)))
+ (b (car lb)))
(if (and a b)
- (mapcar2-append-string func (cdr la) (cdr lb)
- (concatenate 'string accum (funcall func a b)))
+ (mapcar2-append-string func (cdr la) (cdr lb)
+ (concatenate 'string accum (funcall func a b)))
accum)))
(defun append-sublists (list)
(defmacro update-alist (akey value alist &key (test '#'eql) (key '#'identity))
"Macro to support below (setf get-alist)"
- (let ((elem (gensym)))
- `(let ((,elem (assoc ,akey ,alist :test ,test :key ,key)))
- (if ,elem
- (progn
- (setf (cdr ,elem) ,value)
- ,alist)
- (setf ,alist (acons ,akey ,value ,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 remove-alist (key alist &key (test #'eql))
+ "Removes a key from an alist."
+ (remove key alist :test test :key #'car))
+
+(defun delete-alist (key alist &key (test #'eql))
+ "Deletes a key from an alist."
+ (delete key alist :test test :key #'car))
+
(defun alist-plist (alist)
(apply #'append (mapcar #'(lambda (x) (list (car x) (cdr x))) alist)))
(defun plist-alist (plist)
(do ((alist '())
- (pl plist (cddr plist)))
+ (pl plist (cddr pl)))
((null pl) alist)
(setq alist (acons (car pl) (cadr pl) 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)))))))
+ (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))))))
+