1

似乎equal无法正确比较哈希表。这是一个例子

(defun hash-alist (alist)
  "Convert association list to a hash table and return it."
  (let ((my-hash (make-hash-table :test 'equal)))
    (dolist (entry alist)
      (puthash (car entry) (cdr entry) my-hash))
    my-hash))
(setq a '((?a . 1) (?b . 2)))
(setq b (hash-alist a))
(setq c (hash-alist a))
(equal b c)

最后一行代码返回nil。还有其他功能可以比较两个哈希表吗?

4

3 回答 3

2

因为 Emacs 没有内置函数来执行此操作。我写它只是为了以防人们感兴趣:

(defun hash-equal (hash1 hash2)
  "Compare two hash tables to see whether they are equal."
  (and (= (hash-table-count hash1)
          (hash-table-count hash2))
       (catch 'flag (maphash (lambda (x y)
                               (or (equal (gethash x hash2) y)
                                   (throw 'flag nil)))
                             hash1)
              (throw 'flag t))))
于 2013-08-12T21:06:59.733 回答
1

自 2013 年以来,Emacs 有了一个现代哈希表库:ht. 它提供了一个功能丰富的 API,类似于dash列表和树、s字符串、f文件。

在 Emacs 24 中安装第三方库真的很简单,阅读安装说明ht

中没有内置的相等函数ht,所以我们还是要自己写函数。我有两种方法可以测试 2 个哈希表是否相等:

(defun ht-equal-1 (t1 t2)
  (equal (ht-items t1) (ht-items t2)))

(defun ht-equal-2 (t1 t2)
  (and (= (ht-size t1)
          (ht-size t2))
       (ht-map (lambda (k v) (equal (ht-get t1 k) v))
               t2)))

对于小型哈希表,它们都应该很快,但我们不确定哪个对于较大的哈希表更快,所以让我们使用以下方法创建一个相对较大的哈希表ht<-plist

(setq foo-table-1 (ht<-plist (number-sequence 1 10000) 'equal))
(setq foo-table-2 (ht<-plist (number-sequence 1 10000) 'equal))

有一个很棒的 Elisp 函数benchmark-run可以多次运行一个函数或一个 Elisp 表达式,然后报告它所用的时间。让我们运行 2 个函数,每个函数比较我们刚刚创建的 2 个哈希表:

(benchmark-run 1000 (ht-equal-1 foo-table-1 foo-table-2))
;; => (5.36585361 4 0.6110091979999996)
(benchmark-run 1000 (ht-equal-2 foo-table-1 foo-table-2))
;; => (3.708278817 0 0.0)

它似乎ht-equal-2运行得更快,所以你应该使用它。

于 2016-01-12T00:16:30.367 回答
0

我想通过, 和函数的组合hash-table-count,您可以轻松地进行自己的哈希表相等性测试。maphashgethash

于 2013-08-12T12:02:19.233 回答