Re: ANSI Common Lisp, Ch 3, Ex 3
- From: "Geoffrey Summerhayes" <sumrnot@xxxxxxxxxxxxxxxxx>
- Date: Thu, 2 Mar 2006 01:54:13 -0500
"Jason" <jemeade@xxxxxxxxx> wrote in message news:1141272452.925621.101240@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I'm learning Lisp just for fun using Paul Graham's book, "ANSI Common
Lisp". I'm determined to master each chapter before progressing to the
next. Having said that, on page 56 there is the following problem:
3. Define a function that takes a list and returns a list indicating
the number of times each (eql) element appears, sorted from the most
common element to the least common.
(occurences '(a b a d a c d c a)((A . 4) (C. 2) (D. 2) (B. 1))
Well, this "simple" task has been driving me crazy! I must have spent
at least 10 hours working on it. Having said that, I SOLVED IT!!! :)
Great!
Here's my solution:
(setq input '(a b a d a c d c a))
Ok, general consensus is to use the macro SETF over
the special form SETQ, since SETF is more general.
Also, using SET[*] at top level requires undefined
behaviour (although in every implementation I've seen
it works) so it's better to use DEFVAR or DEFPARAMETER
instead.
Lastly, top-level variables are special, they behave
differently than variables declared in a LET, so
it's good practice to give them special names the
standard being to surround them with asterisks.
(DEFVAR *INPUT* '(a b a d a c d c a))
(defun occurences (input-list)
(let ((sorted-list (sort (copy-sequence input-list) 'string<))
(a-list nil))
(setq a-list (occurences-make-alist () sorted-list))
(occurences-sort-alist a-list)))
STRING< is a bad idea, it's defined to work on strings.
Try (OCCURENCES '(1 2 3 1 2 3 1 2 3 4)). Well done on
the COPY-SEQUENCE, you've been paying attention.
(defun occurences-sort-alist (a-list)
(sort a-list 'occurences-greater))
As another practice note: I prefer #' to '.
Makes it easier to spot the reference to
a function rather than just a quoted symbol.
OTOH, I no longer use #'(LAMBDA ...) just (LAMBDA ...)
(defun occurences-greater (node-1 node-2)
(> (cdr node-1) (cdr node-2)))
Others have pointed out that SORT takes an optional
key argument.
(SORT A-LIST #'> :KEY #'CDR)
(defun occurences-make-alist (a-list sorted-list)
(let ((node nil)
(remainder nil))
(if (not (null sorted-list))
(progn
(setq node (occurences-get-token-cons sorted-list))
(setq remainder (occurences-remainder node sorted-list))
(setq a-list (append a-list node (occurences-make-alist a-list
remainder)))))
a-list))
Just a performance note, if you are faced with a choice
of making a list bigger by using APPEND to add an element
to the end of the list or using CONS on the front, CONS
is almost always the winner because APPEND has to go all
the way through the list to find the end. If order is
important you can always REVERSE or NREVERSE the list
when you're done.
(defun occurences-remainder (node sorted-list)
(if (null node)
sorted-list
(subseq sorted-list (cdr (car node)))))
(defun occurences-get-token-cons (sorted-list)
(if (null sorted-list)
nil
(progn
(let ((tok (car sorted-list)) (count 1))
(setq count (occurences-get-token-count tok count (cdr sorted-list)))
(list (cons tok count))))))
(defun occurences-get-token-count (token count input-list)
(if (eql token (car input-list))
(setq count (+ count (occurences-get-token-count token count (cdr
input-list)))))
count)
(occurences input)
;;; END
And, it works! :)
Ok, my version :)
(defun occurences(list)
(let ((counts (make-hash-table :test #'eql)))
(dolist (item list) (incf (gethash item counts 0)))
(sort (loop for key being the hash-keys
in counts using (hash-value count)
collect (cons key count))
#'> :key #'cdr)))
If you haven't yet, download a copy of the hyperspec, you
can find one at www.lispworks.com , it's a wonderful resource.
--
Geoff
.
- Follow-Ups:
- Re: ANSI Common Lisp, Ch 3, Ex 3
- From: Simon Brooke
- Re: ANSI Common Lisp, Ch 3, Ex 3
- From: Jason
- Re: ANSI Common Lisp, Ch 3, Ex 3
- References:
- ANSI Common Lisp, Ch 3, Ex 3
- From: Jason
- ANSI Common Lisp, Ch 3, Ex 3
- Prev by Date: Re: ANSI Common Lisp, Ch 3, Ex 3
- Next by Date: Re: ANSI Common Lisp, Ch 3, Ex 3
- Previous by thread: Re: ANSI Common Lisp, Ch 3, Ex 3
- Next by thread: Re: ANSI Common Lisp, Ch 3, Ex 3
- Index(es):
Relevant Pages
|