Common Lisp中对哈希表平等的自定义测试

时间:2018-05-21 22:02:04

标签: common-lisp hashtable equality

两个哈希表相等的简单测试是(equalp ht1 ht2),它测试(1)相同:测试参数,(2)相同的哈希表计数,(3)相同的键和值,以及( 4)equp值。但是,我需要更快的比较,因为这个简单的测试消耗了大约40%的程序运行时间(根据sbcl中的统计分析)。因此看起来像(1)和(4)以及(3)的一部分是不必要的。以下是尝试减少运行时间(包括coredump的建议改进):

(defun hash-table-equal-keys (ht1 ht2)
  "Determines if all the keys of two hash tables are the same."
  (and (= (hash-table-count ht1) (hash-table-count ht2))
       (loop for key1 being the hash-keys of ht1
           always (gethash key1 ht2))))

但是,对运行时间的影响可以忽略不计。

基本要求仅涉及表中是否存在键,这些键在运行时被强烈访问和更新。还在运行时基于一些变量计算密钥 - 例如,sym1,sym2,...... - 其值取自固定的符号集。目前我正在使用宏进行设置,其中一个方面使用(gethash (list sym1 sym2 ...) ht)构建哈希表访问/更新。但是,除了密钥的构建和列表构建之外,这还需要一个低效的#'equal哈希表。

一种更有效的方法可能是宏构建一个类似(gethash (intern (concatenate 'string (symbol-name sym1) (symbol-name sym2) ...)) ht)的访问,它基本上用字符串连接代替列表构建。它还允许#'eq哈希表。是否存在与此方法相关的任何问题?

更新:更改程序以使用带有连接的#' eq哈希表会导致性能更差。显然,将密钥从列表转换为符号涉及太多的开销。

3 个答案:

答案 0 :(得分:1)

根据您的评论,您有一组符号列表。如果您查找的键每次都进行哈希处理,那么比较这些(在哈希表查找中也会发生)可能会很昂贵。

也许您可以使用在创建时具有更多开销的自定义结构替换散列表,但比较快得多:在创建时,您将内容置于规范顺序(对它们进行排序),然后对它们进行散列(最常见)可能需要一个良好的哈希函数; sxhash通常比速度优化,而不是碰撞阻力。然后比较变为哈希(整数)相等。

答案 1 :(得分:0)

第一个测试条件(= (hash-table-count ht1) (hash-table-count ht2))遍历ht1和ht2。

答案 2 :(得分:0)

之前的澄清改为更多答案:

如前所述,首先创建一个哈希表,将每个可能的符号与整数(或fixnum)相关联。由于少于100个符号,数字的范围可以从1到99.然后在运行时,将给定的符号序列转换为它们各自的整数:例如,(sym1 sym2 sym3) - > (16 88 3)。通过将第一个乘以1,将第二个乘以100,将第三个乘以100x100 = 10,000,可以将它们组合成一个更大的整数,依此类推,如果有更多整数,则可以求和。该组合是有效的,因为它基于整数运算。对于输入整数的任何排列,结果整数应该是唯一的,并且可以在eql哈希表中用于访问原始符号序列。