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))

4
  • 1
    C-h f sort tells you how to sort a list, using a predicate of your choice.
    – NickD
    Commented Mar 21, 2022 at 2:18
  • I need some elaboration for sorting the $words list. Gone with (sort $words '<), which gets sort to complain with sort: Wrong type argument: number-or-marker-p, (This . 1)
    – Dilna
    Commented Mar 21, 2022 at 2:29
  • Was the elaboration in the answer enough?
    – NickD
    Commented Mar 22, 2022 at 21:27
  • The elaboration is enough.
    – Dilna
    Commented Mar 23, 2022 at 0:09

1 Answer 1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.