typestar

word_freq.lisp en Lisp

Cuenta la frecuencia de las palabras de un pasaje incluido e imprime una tabla ordenada.

;; word_freq.lisp: word frequency report over an inline passage.

(defparameter *passage*
  "The quick brown fox jumps over the lazy dog. The dog barks
   and the fox runs. Quick thinking saved the fox that day.")

(defun word-char-p (ch)
  (or (alpha-char-p ch) (char= ch #\')))

(defun split-words (text)
  "Return TEXT as a list of lowercase words with punctuation dropped."
  (let ((words '())
        (start nil))
    (dotimes (i (length text))
      (let ((ch (char text i)))
        (cond ((and (word-char-p ch) (null start))
               (setf start i))
              ((and (not (word-char-p ch)) start)
               (push (string-downcase (subseq text start i)) words)
               (setf start nil)))))
    (when start
      (push (string-downcase (subseq text start)) words))
    (nreverse words)))

(defun tally (words)
  "Return (word . count) pairs, most frequent first, ties alphabetical."
  (let ((counts (make-hash-table :test #'equal))
        (pairs '()))
    (dolist (word words)
      (incf (gethash word counts 0)))
    (maphash (lambda (word count) (push (cons word count) pairs)) counts)
    (sort pairs (lambda (a b)
                  (if (= (cdr a) (cdr b))
                      (string< (car a) (car b))
                      (> (cdr a) (cdr b)))))))

(let* ((words (split-words *passage*))
       (ranked (tally words))
       (singles (remove-if-not (lambda (pair) (= (cdr pair) 1)) ranked)))
  (format t "~d words, ~d unique~%~%" (length words) (length ranked))
  (format t "~12a ~5a~%" "word" "count")
  (dolist (pair (subseq ranked 0 (min 6 (length ranked))))
    (format t "~12a ~5d~%" (car pair) (cdr pair)))
  (format t "~%~d word~:p appeared exactly once~%" (length singles)))

Cómo funciona

  1. split-words recorre el texto carácter por carácter y corta palabras donde word-char-p rechaza.
  2. tally cuenta en una tabla hash creada con :test #'equal, y luego maphash junta pares para sort.
  3. Los empates se rompen alfabéticamente con string<, y ~12a ~5d alinea las filas impresas.

Palabras clave y builtins usados aquí

El intento, en números

Líneas
44
Caracteres a escribir
1490
Tokens
356
Ritmo de tres estrellas
75 tpm

Al ritmo de tres estrellas de 75 tokens por minuto, este intento toma unos 285 segundos.

Escribe este fragmento

Paso 1 de 3 en Bis; paso 25 de 27 en Fundamentos del lenguaje.

← Anterior Siguiente →