【问题标题】:Lisp - Checking if a symbol is in a list of listsLisp - 检查符号是否在列表列表中
【发布时间】:2013-10-30 12:28:59
【问题描述】:

我正在尝试创建一个具有符号/令牌和传入列表的函数

然后该函数将检查列表是否包含符号/令牌。如果是则返回其对应的密钥对,如果不是则返回 nul

我做了一个定义参数:

(defparameter *pairs* 
  '((apple green)
    (banana yellow)
    (grape purple)))

然后我做了一个函数来完成这个任务:

(defun list-pairs (word list)
  (if (eq word list)
    (rest(list)))
  nil))

这样执行时的函数:(list-pairs '(banana) *pairs*) 我不断得到 nul

我想要返回的是黄色,即密钥对

有人可以帮我解释什么是错的。我对 LISP 很陌生

【问题讨论】:

  • 为什么不使用 LISP 哈希机制,如下所述:stackoverflow.com/questions/1837438/…
  • 因为我才刚刚开始学习 lisp,所以我只是在使用更高级的东西之前尝试使用基础知识完成任务:) 即只使用 defun、if 语句、缺点,首先,rest zerop,编号等

标签: list if-statement functional-programming lisp common-lisp


【解决方案1】:
(second (assoc 'banana *pairs*))

给予

YELLOW

编辑:有关assoc 及其使用的关联列表(或简称:alists)的概念的文档,请参阅下面 Joshua Taylor 的评论(非常简短: alists 是由 cons 单元格列表组成的键值数据结构,其中每个 cons 单元格的car 是键,cdr 是值。

关于你自己的代码有什么问题:

在您的if:(eq word list) 的条件下,您正在测试您的论点word 是否与您的论点list 相同。但是您实际上想在list 中查找word,所以这不是正确的条件。

此外,即使条件为真,您评估的结果也是(rest(list))。这是通过调用函数 list 创建的新空列表的其余部分,而不是您的参数 list 的其余部分。

最后,您将在(rest(list)) 之后用第三个右括号关闭if 表达式。因此,即使其他一切都是正确的,最终的 nil 将是您的函数的返回值。您需要将nil 移动到if 表达式的括号中,使其成为else-consequent,并将if 表达式的值作为函数的返回值。

【讨论】:

  • 我很高兴看到assoc 被提及,特别是因为我认为它是“Lisp 基础”之一。我不介意看到一些关于association lists 是什么以及assoc 做什么的讨论......
  • @JoshuaTaylor:同意,如果我添加对assoc 的解释会更好。感谢您提供指向 CLHS 的链接,我将在我的回答中添加对您的评论的引用。 (我没有这样做的一个原因正是因为我认为 Lisp 的每一个体面的介绍都应该提到它的基础。)
【解决方案2】:

你要找的是

(defun list-pairs (word list)
  (if list
    (if (eq (caar list) word)
      (cadar list)
      (list-pairs word (cdr list))))))

或者,使用 let 作为一个小的优化:

(defun list-pairs (word list)
  (if list
    (let ((c (car list)))
      (if (eq (car c) word)
        (cadr c)
        (list-pairs word (cdr list))))))

与进行尾调用优化的 Common Lisp 实现配合得很好;你应该像

一样使用它
(list-pairs 'banana *pairs*)

但在 Common Lisp 中,循环宏通常是首选:

(defun list-pairs (word list)
  (loop for c in list
    when (eq (car c) word)
    return (cadr c)))

【讨论】:

    【解决方案3】:

    作为另一种选择:

    (defun list-pairs (word list)
      (dolist (p list)
        (if (eq word (first p))
          (return (second p)))))
    
    (defparameter *pairs* 
      '((apple green)
        (banana yellow)
        (grape purple)))
    
    (list-pairs 'banana *pairs*)
    YELLOW
    

    【讨论】:

      【解决方案4】:

      你的任务给我留下了一些问题。

      1.) 你的函数应该得到一个符号。但是为什么要这样称呼它:(list-pairs '(banana) *pairs*)(list-pairs 'banana *pairs*) 还不够吗?

      2.) 您是否只想获得配对中第一个元素的匹配项? IE。您希望符号 bananayellow 的结果相同吗?

      如果你只想搜索第一个元素,Rörd 已经提到了assoc,那就完美了。 如果你想检查这对的两个元素,你可以试试remove-if-not

      (defun list-pairs (word list)
        (remove-if-not
         #'(lambda (sublist) (member word sublist))
         list))
      

      【讨论】:

        猜你喜欢
        • 2011-09-02
        • 2015-01-15
        • 1970-01-01
        • 1970-01-01
        • 2017-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多