我有一个像这样的a-list
\n(setf *books* \'(\n ( \n (:title \'Titulo 1)\n (:autor (quote Autor 1) )\n ) \n (\n (:title \'T\xc3\xadtulo 2)\n (:autor (quote Autor 2) )\n )\n ; (...) \n))\nRun Code Online (Sandbox Code Playgroud)\n我需要创建一个根据书名查找书籍的函数。阅读文档后我尝试:
\n(defun string-include (string1 string2)\n (let* ((string1 (string string1)) (length1 (length string1)))\n (if (zerop length1)\n nil \n (labels ((sub (s)\n (cond\n ((> length1 (length s)) nil)\n ((string= string1 s :end2 (length string1)) string1)\n (t (sub (subseq s 1))))))\n (sub (string string2)))))\n)\n(\n defun buscar (books text)\n (remove-if-not \n (lambda (book)\n ;(search cadena (assoc :title book))\n ;(string-include (string (cddr (assoc :title book))) cadena)\n (string= (format nil (cddr (assoc :title book))) (format nil book))\n )\n books)\n)\nRun Code Online (Sandbox Code Playgroud)\n我找不到这本书,我做错了什么?
\n请注意,我所做的(评论的)测试均无效
\n您的数据结构不是关联列表。Alist 是一个对的列表,因此您应该像这样创建它:
(defparameter *books* '(((:title . "Titulo 1")
(:autor . "Autor 1"))
((:title . "Titulo 2")
(:autor . "Autor 2"))))
Run Code Online (Sandbox Code Playgroud)
注意三件事:
setf来初始化全局变量 - 您应该使用defparameterordefvar作为全局变量和let局部变量。这可以帮助您:defvar、defparameter、setf 和 setq 之间有什么区别
quote,因为带引号的数据结构内的表达式也会被带引号。另外,这个调用(quote Autor 1)没有任何意义——quote只用一个参数调用。这可以帮助你:何时在 Lisp 中使用 ' (或引号)?
我不会发表string-include太多评论——但有些电话看起来很奇怪。为什么要调用(string string1)(将字符串转换为字符串)或(string= string1 s :end2 (length string1))(string=比较字符串,但结果(length string1)将是数字)?您不仅应该编写更小且可测试的函数,还应该在 REPL 中不断测试您的代码,以确保一切按您的预期工作。
该buscar函数看起来好一点(但它仍然包含一些奇怪的调用,就像(format nil book)您之前没有测试过的那样),您可以将其更改为如下所示:
(defun buscar (books title)
(remove-if-not (lambda (book) (string= (cdr (assoc :title book)) title))
books))
Run Code Online (Sandbox Code Playgroud)
测试:
> (buscar *books* "Titulo 1")
(((:TITLE . "Titulo 1") (:AUTOR . "Autor 1")))
Run Code Online (Sandbox Code Playgroud)
或者你可以使用find:
(defun search-by-title (books title)
(find title books :test #'string= :key (lambda (book) (cdr (assoc :title book)))))
> (search-by-title *books* "Titulo 1")
((:TITLE . "Titulo 1") (:AUTOR . "Autor 1"))
Run Code Online (Sandbox Code Playgroud)
编辑:或find-if与search(部分匹配/子字符串):
(defun search-by-title (books title)
(find-if (lambda (book) (search title (cdr (assoc :title book))))
books))
> (search-by-title *books* "2")
((:TITLE . "Titulo 2") (:AUTOR . "Autor 2"))
Run Code Online (Sandbox Code Playgroud)