使用构造键进行高效的哈希表访问

时间:2016-12-04 22:13:27

标签: data-structures common-lisp hashtable

Common Lisp允许任何lisp对象充当哈希表键。但是,如果您只想使用对象的一部分作为键,该怎么办?例如,在

(defstruct action
  (name nil :type symbol)
  (parameters nil :type list)
  (time 0 :type fixnum)
  (database nil :type hash-table))

时隙不适合equp散列情况。使用(部分)lisp对象作为密钥访问哈希表的好策略是什么?一种方法可能使用像(list (action-name act1) (action-parameters act1) (action-database act1))这样的密钥,但这似乎效率很低。另一种方法可能只使用三个适当的槽创建动作defstruct的子结构,并使用该子结构作为键,但这似乎只是为了哈希表访问的目的。还有其他方法可以更好地运作吗?

1 个答案:

答案 0 :(得分:0)

我将使用here中的Common Lisp库,例如

cl-custom-hash-table

然后转到你的代码,首先是你创建一个这样的动作:

CL-USER>  (setq action-1 (make-action 
   :parameters '(1 2 3) 
   :time 45))

产生此错误:

The value NIL is not of the expected type HASH-TABLE.
   [Condition of type TYPE-ERROR]

因此您需要将定义更改为以下内容:

CL-USER> (defstruct action
  (name nil :type symbol)
  (parameters nil :type list)
  (time 0 :type fixnum)
  (database (make-hash-table) :type hash-table))
ACTION
CL-USER>  (setq action-1 (make-action 
   :parameters '(1 2 3) 
   :time 45))

#S(ACTION :NAME NIL :PARAMETERS (1 2 3) :TIME 45 :DATABASE #<HASH-TABLE :TEST EQL size 0/60 #x3020012E708D>)

然后你应该定义一个相同时间的函数或者你需要的函数如下: 访问数据

CL-USER> (action-time action-1)
45

创建另一个动作

CL-USER>  (setq action-2 (make-action 
   :parameters '(1 2 3) 
   :time 102))

#S(ACTION :NAME NIL :PARAMETERS (1 2 3) :TIME 102 :DATABASE #<HASH-TABLE :TEST EQL size 0/60 #x3020012FE58D>)

创建测试功能

CL-USER> (defun equal-actions-by-time (a1 a2) (= (action-time a1) (action-time a2)))
EQUAL-ACTIONS-BY-TIME

定义哈希函数:

CL-USER> (defun hash-action (a) (action-time a))
HASH-ACTION

创建你的哈希

CL-USER> (define-custom-hash-table-constructor make-action-hash :test equal-actions-by-time :hash-function hash-action)
MAKE-ACTION-HASH
CL-USER> (defparameter *foo-hash* (make-action-hash) "variable for stackoverflow")
*FOO-HASH*

试一试:

CL-USER>  (setf (gethash action-1 *foo-hash*) 1
          (gethash action-2 *foo-hash*) 10)
10

CL-USER>  (gethash action-1 *foo-hash*)
1
T

如果分发在本机支持自定义TEST / HASH函数的实现中有效,则可以避免使用库,如果不能,则可以使用with-custom-hash-table

在optimus案例中,您可以按照以下方式工作:

CL-USER> (defparameter *foo-hash* (make-hash-table :test 'equal-actions-by-time :hash-function 'hash-action))
*FOO-HASH*
CL-USER>  (setf (gethash action-1 *foo-hash*) 1
          (gethash action-2 *foo-hash*) 10)
10
CL-USER>  (gethash action-1 *foo-hash*)
1
T