1

Have the following code that counts the number of times words are used. I want to list the results sorted by the number of counts.


    (defun rk-word-analysis (reg-beg reg-end)
      "Count times words are used in a region, ignoring punctuation."
    
      (interactive "r")
    
      (let ($words)
    
        (save-excursion
          (goto-char reg-beg)
          (while (re-search-forward "\\w+" reg-end t)
        (let* (($word (intern (match-string 0)))
               ($cell (assq $word $words)))
          (if $cell
              (setcdr $cell (1+ (cdr $cell)))
            (setq $words (cons (cons $word 1) $words))))))
        (when (interactive-p)
          (message "%S" $words))
    
        $words))

Drew
  • 75,699
  • 9
  • 109
  • 225
Dilna
  • 1,173
  • 3
  • 10

1 Answers1

1

Use the sort function with the appropriate predicate. Since the list that you want to sort is a list of pairs, (word . count), you cannot compare using < which can only compare numbers: (< '("foo" . 3) '("bar" . 7)) does not work because < cannot compare pairs. Since you want to sort the list by increasing order of the count, you have to select the count part to compare. So the appropriate predicate would be:

(lambda (x y) (< (cdr x) (cdr y))

In other words, to compare x and y, you take the cdr of each (i.e. the count part of the pair) and compare them with < - this works since you are comparing numbers.

Here's an example of how to call sort:

;; initialize $words
(setq $words '(("foo" . 5) ("bar" . 3) ("baz" . 4)))
(("foo" . 5) ("bar" . 3) ("baz" . 4))

;; sort the list according to the predicate
(setq sorted-list (sort $words (lambda (x y) (< (cdr x) (cdr y)))))
(("bar" . 3) ("baz" . 4) ("foo" . 5))

;; how the sorted list looks
sorted-list
(("bar" . 3) ("baz" . 4) ("foo" . 5))

EDIT: This is obviously ascending order. For descending order, replace < with > in the predicate.

NickD
  • 27,023
  • 3
  • 23
  • 42