LISP 在列表中查找项目

Jos*_*rán 0 lisp common-lisp

我有一个像这样的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))\n
Run 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)\n
Run Code Online (Sandbox Code Playgroud)\n

我找不到这本书,我做错了什么?

\n

请注意,我所做的(评论的)测试均无效

\n

Mar*_*ůda 8

您的数据结构不是关联列表。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-ifsearch(部分匹配/子字符串):

(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)