对不起,标题令人费解,我尽力使它有意识。好吧,如果您有更好的想法,请更改它!
不要让您感到困惑,这是Emacs Lisp loop
,而不是 Common Lisp:
(defun hxswfml-build-trie (alist)
"Builds a trie (a list, containing number of hash-maps, each hash-map
uses single character for a key, except for `t' symbol, which, if present
as a key is the key for the value one has to substitute with."
(loop for (key . value) in alist
with trie = (make-hash-table)
do (loop for c across key
with branch =
(or (gethash c trie)
(puthash c (make-hash-table) trie))
with first-time = t
do (if first-time (setq first-time nil)
(setq branch
(or (gethash c branch)
(puthash c (make-hash-table) branch))))
finally (puthash t value branch))
finally (return trie)))
这会将 alist 转换为由哈希表组成的树,其中每个表都包含键,这些键是我稍后要搜索和替换的字符串的字符。这需要优化在大量文本中搜索具有可能相似前缀的多个键,然后用相应的键替换它们。
问题是,在内部循环中,我想初始化branch
,trie
然后在所有以后的迭代中将其设置为新的哈希表(为尚未属于已知前缀的字符创建)或哈希表它已经为前缀中的字符创建了。
理想情况下,它看起来像:
for branch = (or (and branch (gethash c branch)) (puthash c (make-hash-table) trie))
;; ^-----------------^------- cannot reference it here
这就是为什么我有愚蠢的first-time
旗帜,我本可以避免的。我可以以某种方式使用initially
表单,或者以其他方式重组函数来避免这个标志和额外if
的东西吗?这个函数的速度不是很重要(搜索应该很快,但树的构建不需要),但它看起来很丑:)