Exercise Problem

Discussion of Common Lisp
Post Reply
Posts: 1
Joined: Wed May 27, 2015 6:58 am

Exercise Problem

Post by ironzep » Wed May 27, 2015 7:23 am


I have an exercise to make, and I don't have any idea how to make it. There goes my problem: I have a lot of data in a txt file. Each line of this txt file has the name of a person, its height and its own evaluation of who is tall and who is small. It's like this:

"PEDRO ALVES 1.51 I think that a small person is under 1.65 and above 2.13 is high."

There are five patterns of phrases. So, I need to work on this in Lisp and show who is the tallest person, who is the smallest person, and through the evaluation of each person, who is the tallest person and who is the smallest person. Thanks!

David Mullen
Posts: 78
Joined: Mon Dec 01, 2014 12:29 pm

Re: Exercise Problem

Post by David Mullen » Fri May 29, 2015 12:42 pm

Would it be acceptable to use the Common Lisp READ function here? Are the height measurements intended as floating-point numbers? Fixed-point? If the numbers are fixed-width—one digit before the decimal point, and two digits after it—then I'll just go ahead and use string-wise comparisons on the fields without instantiating any particular kind of number. I'll also assume I can read the text file into one big string and work with displacements into that. The TALLEST-PERSON function could work like this:

Code: Select all

(defvar *text*
  (make-array 8192
              :element-type 'character
              :fill-pointer 0
              :adjustable t))

(defun read-text-file (pathname)
  (with-open-file (stream pathname)
    (setf (fill-pointer *text*) 0)
    (loop for char = (read-char stream nil nil)
          while char do (vector-push-extend char *text*))))

(defun parse-name (start)
  (loop with space-count = 0
        for index from start below (length *text*)
        for char = (char *text* index)
        when (char= char #\Space)
        do (incf space-count)
        when (= space-count 2)
        return (values (make-array
                        (- index start)
                        :element-type 'character
                        :displaced-index-offset start
                        :displaced-to *text*)
        ;; Didn't find the name at all.
        finally (return (values nil index))))

(defun find-height (start)
  (loop for index from start below (length *text*)
        for char = (char *text* index)
        when (digit-char-p char)
        return (values index (+ index 4))))

(defun height< (index1 index2)
  (string< *text* *text*
           :start1 index1 :start2 index2
           :end1 (+ index1 4) :end2 (+ index2 4)))

(defstruct person
  name height

(defun parse-line (start)
  (let (name height small-mark tall-mark)
    (when (multiple-value-setq (name start) (parse-name start))    
      (multiple-value-setq (height start) (find-height start))
      (multiple-value-setq (small-mark start) (find-height start))
      (multiple-value-setq (tall-mark start) (find-height start))
      (values (make-person :name name
                           :height height
                           :small-mark small-mark
                           :tall-mark tall-mark)
              ;; Find the end of the line.
              (loop while (< start (length *text*))
                    if (char= (char *text* start) #\Newline) return (1+ start)
                    else do (incf start) finally (return start))))))

(defvar *people*
  (loop with start = 0 and person initially (read-text-file "people.txt")
        do (multiple-value-setq (person start) (parse-line start))
        while person collect person))

(defmethod print-object ((person person) stream)
  (cond (*print-escape* (call-next-method))
        (t (write-string (person-name person) stream))))

(defun tallest-person ()
  (loop with current-target = (car *people*)
        for person in (cdr *people*)
        when (height< (person-height current-target)
                      (person-height person))
        do (setq current-target person)
        finally (return current-target)))

Post Reply