【问题标题】:returning list from dolist loop, instead return NIL从 dolist 循环返回列表,而不是返回 NIL
【发布时间】:2013-11-07 15:07:33
【问题描述】:

你能帮我写代码吗,我不明白为什么它没有返回我的wireList,它只是返回NIL

(defun table-wires-position(inputTable inputPosition)
   (let ((wireList () ))
     (dolist (x (table-wires inputTable) wireList)
        (if (or (equal-position-p (wire-OriginCoin x) inputPosition) 
                (equal-position-p (wire-destinCoin x) inputPosition))
                   (cons x wireList)))))

【问题讨论】:

    标签: lisp common-lisp


    【解决方案1】:

    首先,请注意,您在编写如下代码时在技术上是正确的 (the best kind of correct):

    (let ((wireList ()))
      (dolist (x (table-wires inputTable) wireList)
        …)
    

    这确实意味着dolist 正在返回wireList。问题标题“从 dolist 循环返回列表,而不是返回 NIL”有点误导,因为:(i)nil 一个列表,所以你返回一个列表; (ii) 你正在返回wireList。问题是在执行dolist 的过程中,您实际上并没有修改wireList。函数cons 只是返回一个新的 cons 单元格;它不会修改位置,因此您不会修改wireList。您可以改用push,就像下面的代码一样。由于您使用的是没有 else 部分的if,因此您可以使用when

    (defun table-wires-position(inputTable inputPosition)
      (let ((wireList ()))
        (dolist (x (table-wires inputTable) wireList)
          (when (or (equal-position-p (wire-OriginCoin x) inputPosition) 
                    (equal-position-p (wire-destinCoin x) inputPosition))
            (push x wireList))))) ; or (setf wireList (cons x wireList))
    

    在风格节点上,我经常使用&aux variables 来表示这类结果变量;它避免了嵌套级别:

    (defun table-wires-position (inputTable inputPosition &aux (wireList '()))
      (dolist (x (table-wires inputTable) wireList)
        (when (or (equal-position-p (wire-OriginCoin x) inputPosition) 
                  (equal-position-p (wire-destinCoin x) inputPosition))
          (push x wireList))))
    

    请注意,通过push将元素添加到列表中,您将按照与inputTable相反的顺序获取它们。如果需要,您可以通过返回 (nreverse wireList) 以相同的顺序获取它们。更好的是,由于您实际上只是返回一个删除了某些元素的列表,您不妨使用remove-if-not

    (defun table-wires-position (inputTable inputPosition)
      (remove-if-not #'(lambda (x) 
                         (or (equal-position-p (wire-OriginCoin x) inputPosition) 
                             (equal-position-p (wire-destinCoin x) inputPosition)))
                     inputTable))
    

    【讨论】:

    • @Baggers 哎呀!接得好。现已修复。
    【解决方案2】:

    Joshua 的答案是这里的方法,但作为附录,这是使用循环宏的版本。

    (defun table-wires-position (input-table input-position)
      (loop :for x :in input-table 
         :if (or (equal-position-p (wire-origin-coin x) input-position) 
                 (equal-position-p (wire-destin-coin x) input-position))
         :collect x))
    

    也不要使用驼峰命名,因为符号不区分大小写,所以以下都是相同

    inputPosition INputPosition INPUTPOSITION iNpUtPoSiTiOn
    

    始终使用连字符,例如输入位置

    【讨论】:

    • Nitpick:阅读器(默认情况下)将所有内容大写,因此当它遇到 inputPosition INputPosition INPUTPOSITION iNpUtPoSiTiOn 时,它会将字符串大写并实习,因此您会得到相同的符号。在(setf (readtable-case *readtable*) :preserve) 之后,您将获得四个不同的符号。请参阅23.1.2.1 Examples of Effect of Readtable Case on the Lisp Reader 了解更多信息。 :invert 的情况下,如果您使用骆驼情况,则很方便,因为defun 仍然是'DEFUN,但ZwCreateFile'|ZwCreateFile|
    【解决方案3】:

    小补充:

    如果一个宏以do 开头,就像dolist 一样,它只会进行迭代,并针对副作用进行迭代。因此,如果需要,将迭代结果放在某个地方是用户的任务。

    如果它以collect 开头或允许在主体中的某处使用collect 子句,那么它应该返回一个迭代结果列表。 loop 宏就是这样一种构造,但人们可能会在图书馆或书籍中找到其他迭代构造。

    【讨论】:

    • 请注意,OP 知道dolist 可以在列表形式之后返回非nil 值; OP 的dolist 开始是(dolist (x (table-wires inputTable) wireList) ...),甚至似乎试图用(cons x wireList) 建立wireList。不过,docollect 的区别很好!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-04
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 2017-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多