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的子结构,并使用该子结构作为键,但这似乎只是为了哈希表访问的目的。还有其他方法可以更好地运作吗?
答案 0 :(得分:0)
我将使用here中的Common Lisp库,例如
然后转到你的代码,首先是你创建一个这样的动作:
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