按值对哈希表进行排序的最佳方法是什么?

z_a*_*xis 6 lisp clisp

现在我必须在排序之前将hastable复制到列表中:

(defun good-red ()
  (let ((tab (make-hash-table)) (res '()))
    (dotimes (i 33) (setf (gethash (+ i 1) tab) 0))
    (with-open-file (stream "test.txt")
        (loop for line = (read-line stream nil)
             until (null line)
             do
                (setq nums (butlast (str2lst (substring line 6))))
                (dolist (n nums) (incf (gethash n tab)))
                ))
    **(maphash #'(lambda (k v) (push (cons k v) res)) tab)**
    (setq sort-res (sort res #'< :key #'cdr))
    (reverse (nthcdr (- 33 18) (mapcar #'car sort-res))) ))
Run Code Online (Sandbox Code Playgroud)

顺便说一句,获取列表的前N个元素的更好方法是什么?

小智 12

Vatine的答案在技术上是正确的,但对于某人提出这个问题的直接问题可能不是很有帮助.使用哈希表来保存计数器集合,然后按分数选择前N项的常见情况可以这样做:

;; convert the hash table into an association list
(defun hash-table-alist (table)
  "Returns an association list containing the keys and values of hash table TABLE."
  (let ((alist nil))
    (maphash (lambda (k v)
               (push (cons k v) alist))
             table)
    alist))

(defun hash-table-top-n-values (table n)
  "Returns the top N entries from hash table TABLE. Values are expected to be numeric."
  (subseq (sort (hash-table-alist table) #'> :key #'cdr) 0 n))
Run Code Online (Sandbox Code Playgroud)

第一个函数将哈希表的内容作为列表中的一系列缺点对返回,这称为关联列表(键/值对的典型列表表示).大多数Lisp爱好者已经掌握了这个功能的变体,因为它是如此常见的操作.此版本来自亚历山大图书馆,该图书馆在CL社区中使用得非常广泛.

第二个函数使用SUBSEQ从返回的列表中获取前N个项,方法是使用每对的CDR作为键对第一个函数返回的alist进行排序.更改:#'car的键将按哈希键排序,将#'>更改为#'<将反转排序顺序.