From ... Path: supernews.google.com!sn-xit-02!sn-xit-03!supernews.com!news.tele.dk!193.190.198.17!newsfeeds.belnet.be! news.belnet.be!skynet.be!newsfeed2.news.nl.uu.net!sun4nl!not-for-mail From: Arthur Lemmens Newsgroups: comp.lang.lisp Subject: Re: Q: on hashes and counting Date: Mon, 23 Oct 2000 00:50:02 +0200 Organization: Kikashi Software Lines: 129 Message-ID: <39F36F1A.B8F19D20@simplex.nl> References: <8sl58e$ivq$1@nnrp1.deja.com> <878zrlp1cr.fsf@orion.bln.pmsf.de> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Trace: porthos.nl.uu.net 972255051 2606 193.78.46.221 (22 Oct 2000 22:50:51 GMT) X-Complaints-To: abuse@nl.uu.net NNTP-Posting-Date: 22 Oct 2000 22:50:51 GMT X-Mailer: Mozilla 4.5 [en] (Win98; I) X-Accept-Language: en Xref: supernews.google.com comp.lang.lisp:2515 Pierre R. Mai wrote: > ;;; The following functions are based on the versions by Arthur > ;;; Lemmens of the original code by Bernard Pfahringer posted to > ;;; comp.lang.lisp. I only renamed and diddled them a bit. > > (defun partition [snip] > ;; DO: Find a more efficient way to take care of :from-end T. > (when from-end > (setf seq (reverse seq)) > (psetf start (- len end) > end (- len start))) I've written a different version now for dealing with :FROM-END T. It doesn't call REVERSE anymore, which makes it more efficient. Also, I prefer the new semantics. Stuff like (split #\space "one two three " :from-end t) now returns ("three" "two" "one") which I find a lot more useful than ("eerht" "owt" "eno") If you prefer the latter, it's easy enough to use (split #\space (reverse "one two three ")) Here it is (feel free to use this code any way you like): (defun SPLIT (delimiter seq &key (maximum nil) (keep-empty-subseqs nil) (from-end nil) (start 0) (end nil) (test nil test-supplied) (test-not nil test-not-supplied) (key nil key-supplied)) "Return a list of subsequences in delimited by . If :keep-empty-subseqs is true, empty subsequences will be included in the result; otherwise they will be discarded. If :maximum is supplied, the result will contain no more than :maximum (possibly empty) subsequences. The second result value contains the unsplit rest of the sequence. All other keywords work analogously to those for CL:POSITION." ;; DO: Make ":keep-delimiters t" include the delimiters in the result (?). (let ((len (length seq)) (other-keys (nconc (when test-supplied (list :test test)) (when test-not-supplied (list :test-not test-not)) (when key-supplied (list :key key))))) (unless end (setq end len)) (if from-end (loop for right = end then left for left = (max (or (apply #'position delimiter seq :end right :from-end t other-keys) -1) (1- start)) unless (and (= right (1+ left) ) (not keep-empty-subseqs)) ; empty subseq we don't want if (and maximum (>= nr-elts maximum)) ;; We can't take any more. Return now. return (values subseqs (subseq seq start right)) else collect (subseq seq (1+ left) right) into subseqs and sum 1 into nr-elts until (<= left start) finally return (values subseqs (subseq seq start (1+ left)))) (loop for left = start then (+ right 1) for right = (min (or (apply #'position delimiter seq :start left other-keys) len) end) unless (and (= right left) (not keep-empty-subseqs)) ; empty subseq we don't want if (and maximum (>= nr-elts maximum)) ;; We can't take any more. Return now. return (values subseqs (subseq seq left end)) else collect (subseq seq left right) into subseqs and sum 1 into nr-elts until (= right end) finally return (values subseqs (subseq seq right end)))))) Here are some examples of how you can use this: CL-USER 2 > (split #\space "word1 word2 word3") ("word1" "word2" "word3") "" CL-USER 3 > (split #\space "word1 word2 word3" :from-end t) ("word3" "word2" "word1") "" CL-USER 4 > (split nil '(a b nil c d e nil nil nil nil f) :maximum 2) ((A B) (C D E)) (F) CL-USER 5 > (split #\space "Nospaceshere.") ("Nospaceshere.") "" CL-USER 6 > (split #\; "12;13;;14" :keep-empty-subseqs t) ("12" "13" "" "14") "" CL-USER 7 > (split #\; "12;13;;14" :keep-empty-subseqs t :from-end t) ("14" "" "13" "12") "" CL-USER 8 > (split #\space "Nospaceshere. ") ("Nospaceshere.") ""