;;; -*- Mode:LISP; Package:SYSTEM-INTERNALS; Readtable:CL -*- (defun myfind-if (predicate sequence &key from-end (start 0) end key) "Return the first element of SEQUENCE that satisfies PREDICATE. Value is NIL if no element satisfies PREDICATE. SEQUENCE can be a list or an array. KEY, if non-NIL, is a function to be applied to each element to get a key, which is passed to PREDICATE. If KEY is NIL, the element itself is used. START and END are indices restricting substitution to a subsequence of SEQUENCE. They default to 0 and NIL (which means the end of SEQUENCE). Elements outside that range are not tested. If FROM-END is non-NIL, the value is the LAST element in SEQUENCE (or specified subsequence) that satisfies the predicate." (check-type sequence sequence) (values (myfind-1 nil sequence start end nil nil key from-end predicate))) (defun myfind-if-not (predicate sequence &key from-end (start 0) end key) "Like MYFIND-IF but looks for an element which does NOT satisfy PREDICATE." (check-type sequence sequence) (values (myfind-1 nil sequence start end nil t key from-end predicate))) (defun myfind (item sequence &key from-end test test-not (start 0) end key) "Return first element of SEQUENCE that matches ITEM. Value is NIL if no element matches. SEQUENCE can be a list or an array. TEST is a function of two args to use to compare ITEM against an element (or key). An element matches when the TEST function returns non-NIL. Alternatively, specify as TEST-NOT a function to use which returns NIL if there is a match. KEY, if non-NIL, is a function to be applied to each element to get a key, which is passed to TEST or TEST-NOT. If KEY is NIL, the element itself is used. START and END are indices restricting substitution to a subsequence of SEQUENCE. They default to 0 and NIL (which means the end of SEQUENCE). Elements outside that range are not tested. If FROM-END is non-NIL, the value is the LAST element in SEQUENCE (or specified subsequence) that matches." (check-type sequence sequence) (values (myfind-1 item sequence start end (or test-not test) (not (null test-not)) key from-end nil))) (defun myfind-1 (item sequence &optional (start 0) end test invertp key from-end one-arg-predicate &aux reslt) (declare (values item index)) (format t "~&invertp is ~s" invertp) (if (and from-end (arrayp sequence)) (do ((index (1- (or end (length sequence))) (1- index)) elt) ((< index start) nil) (setq elt (if key (funcall key (cl:aref sequence index)) (cl:aref sequence index))) (when (eq invertp (not (cond (one-arg-predicate (funcall one-arg-predicate elt)) (test (funcall test item elt)) (t (eql item elt))))) (return (values (cl:aref sequence index) index)))) (do ((index (seq-start sequence start)) (i start (1+ i)) (stop-index (if (consp end) end (seq-end sequence end))) last-pos elt) ((eq index stop-index) (if last-pos (values elt last-pos))) (setq elt (key-fetch-inc key sequence index)) (setq reslt (cond (one-arg-predicate (funcall one-arg-predicate elt)) (test (funcall test elt item)) (t (eql item elt)))) (format t "~&~s vs. ~s is ~s" item elt reslt) (when (eq (not invertp) reslt) (format t "~&comparison succeeded ~s ~s" item elt) (if from-end (setq last-pos i) (return (values (elt sequence i) i)))) (format t "~&comparison failed ~s ~s" item elt)) ))