Skip to content

从哈希表中移除值

哈希表(hash table)是 Lisp 中用于存储键值对的基本数据结构,能提供高效的数据检索。在本章中,你将学习在 Common Lisp 中从哈希表移除条目的现代、惯用方法。

从哈希表中移除键值对的主要函数是 REMHASH。它接受一个键和一个哈希表作为参数,如果对应的条目存在则将其移除,并就地修改该哈希表。

(remhash key hash-table) -> generalized-boolean
  • key:你想要移除的条目的键。
  • hash-table:要修改的哈希表。
  • 返回值:如果找到并移除了条目,REMHASH 返回 T,否则返回 NIL。

让我们通过一个完整的示例来演示如何创建哈希表、填充数据、移除项并验证结果。我们将使用 let 来创建一个词法作用域(lexically scoped)的哈希表,这在示例中是一个最佳实践,可以避免污染全局命名空间。

(let ((product-prices (make-hash-table :test #'equal)))
;; 1. 使用一些产品数据填充哈希表
(setf (gethash "Laptop" product-prices) 1200)
(setf (gethash "Mouse" product-prices) 25)
(setf (gethash "Keyboard" product-prices) 75)
(format t "Original table: ~a~%" product-prices)
(format t "Price of a Mouse before removal: $~a~%~%" (gethash "Mouse" product-prices))
;; 2. 从哈希表中移除 'Mouse' 条目
(let ((removed-p (remhash "Mouse" product-prices)))
(if removed-p
(format t "Successfully removed the 'Mouse' entry.~%")
(format t "'Mouse' entry was not found.~%")))
;; 3. 验证条目已被移除
(multiple-value-bind (price found-p) (gethash "Mouse" product-prices)
(format t "~%Checking for 'Mouse' after removal:~%")
(if found-p
(format t "Entry still exists with price: $~a~%" price)
(format t "Entry for 'Mouse' no longer exists.~%")))
(format t "Final table: ~a~%" product-prices))
原始表: #<HASH-TABLE :TEST EQUAL :COUNT 3 {1005A...}>
移除前鼠标的价格:$25
成功移除了 'Mouse' 条目。
移除后检查 'Mouse':
'Mouse' 的条目不再存在。
最终表: #<HASH-TABLE :TEST EQUAL :COUNT 2 {1005A...}>

创建哈希表时,:test 函数至关重要。它决定了键是如何比较的。

  • #'eql(默认值):比较相同类型和值的数字,或内存中的相同对象。适用于符号和数字。
  • #'equal:按字符比较字符串,或按内容比较列表和向量。对于字符串键请使用此项。
  • #'equalp:一个更宽松的 equal 版本,忽略字符串的大小写和数字类型差异。

gethash 返回两个值:与键关联的值(如果未找到则为 NIL),以及一个布尔值(T 或 NIL)指示是否找到了键。键可能存在但其值为 NIL,因此你必须检查第二个返回值以进行准确的存在性检查。

;; 错误的方式(如果值为 NIL 则失败)
(if (gethash key table))
;; 正确的方式
(multiple-value-bind (value found-p) (gethash key table)
(if found-p
;; 找到了键,对 'value' 进行操作
...))

现在你已经知道如何使用 remhash 有效地从 Common Lisp 哈希表中移除条目了。通过遵循现代最佳实践,例如使用 let 进行局部作用域、选择正确的 :test 函数以及正确检查返回值,你可以编写出健壮且可预测的代码。