【问题标题】:How to print the elements in odd positions in a list using an iterative function in Lisp?如何使用 Lisp 中的迭代函数打印列表中奇数位置的元素?
【发布时间】:2018-01-16 02:32:29
【问题描述】:

我必须在 lisp 中创建一个递归函数,它接受一个列表并创建另一个列表,其中仅包含给定列表中奇数位置的元素。

如果我有(1 2 3 4 5),我必须输出(1 3 5)

我这里有一个代码:

(defun pozpar(lst) (do(
(l lst (cddr l)) 
(x '() (cons x (car l))))
((null l) x)))

这个输出:

(5 3 1)

我知道cons 在开头添加了元素,我尝试使用appendlist,但没有任何效果。

【问题讨论】:

  • 有很多 Lisps。看起来你在这里使用的是 Common Lisp,所以我建议为你正在使用的 specific Lisp 添加一个标签。
  • 这看起来不像一个递归函数。没有使用递归。

标签: lisp common-lisp


【解决方案1】:

最简单的方法是reverse结果:

(defun pozpar (lst)
  (do ((l lst (cddr l))
       (x '() (cons (car l) x)))
      ((null l)
       (nreverse x))))

(pozpar '(1 2 3 4 5))
==> (1 3 5)

注意事项

  1. 这个返回,而不是输出你想要的值。

  2. 预置值并恢复结果是一种常见的 Lisp 编码模式。

  3. 由于append 的参数长度是线性,因此在循环中使用它会产生二次代码。

  4. 我格式化了standard Lisp way 中的代码。如果你使用这种风格,lispers 将更容易阅读你的代码,因此更愿意帮助你。

【讨论】:

    【解决方案2】:

    使用loop 可以很容易地按照您处理它们的顺序获取元素。它也是最有效的,也是唯一能保证使用所有长度参数的方法:

    (defun pozpar1 (lst)
      (loop :for e :in lst :by #'cddr 
            :collect e)))
    

    如果你真的想要递归,我会用一个累加器来完成,最后是线性更新反向:

    (defun pozpar2 (lst)
      (labels ((helper (lst acc)
                 (if (endp lst)
                     (nreverse acc)
                     (helper (cddr lst) (cons (car lst) acc)))))
        (helper lst '())))
    

    然而,经典的非尾递归版本看起来像这样:

    (defun pozpar3 (lst)
      (if (endp lst)
          '()
          (cons (car lst) (pozpar3 (cddr lst)))))
    

    【讨论】:

      【解决方案3】:

      我认为这是一种更简单的解决方案:

      (defun popzar (lst)
        (cond
        ((null lst) nil)
        ( t (cons  (car lst) (popzar (cdr (cdr lst)))))
      ))
      

      它首先检查列表是否为空,如果不是,则使用第一个元素创建一个新列表,并使用列表的其余部分(第二个元素除外)再次调用自身。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-10-03
        • 2012-09-08
        • 1970-01-01
        • 1970-01-01
        • 2016-06-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多