繁体   English   中英

在Lisp函数中使用带有缺点的嵌套汽车

[英]Using nested car with cons in a lisp function

我正在做一个递归的Lisp函数,该函数需要两个列表并创建索引对的子列表

例如:放入(ABCD)和(1 2 3 4)并得到((1 A)(2 B)(3 C)(4 D))

但是,我在使用汽车和缺点时难以进入所说的子列表。 这是我的代码:

(DEFUN zipper (a b)
    (if (= (OR (list-length a) (list-length b)) 0)
        (setq c NIL)
        (progn (zipper (cdr a) (cdr b))
        (cons '((car a) (car b)) c))
    )
)

我玩了一会儿,似乎大部分时间都无法用汽车创建列表。 另外,我正在使用CLISP。 有任何想法吗?

谢谢!

总体思路朝着正确的方向发展。 但是,还有很多问题。 我们来看一下。

(DEFUN zipper (a b)
    (if (= (OR (list-length a) (list-length b)) 0)
        (setq c NIL)
        (progn (zipper (cdr a) (cdr b))
        (cons '((car a) (car b)) c))
    )
)

第一个缩进:

(DEFUN zipper (a b)
  (if (= (OR (list-length a) (list-length b)) 0)
      (setq c NIL)
      (progn (zipper (cdr a) (cdr b))
        (cons '((car a) (car b)) c))                 ; <--
    )
  )

下一个悬挂的括号:

(DEFUN zipper (a b)
  (if (= (OR (list-length a) (list-length b)) 0)
      (setq c NIL)
      (progn (zipper (cdr a) (cdr b))
        (cons '((car a) (car b)) c))))

对于真实情况,请在IF中返回空列表:

(defun zipper (a b)
  (if (= (OR (list-length a) (list-length b)) 0)
      nil
      (progn (zipper (cdr a) (cdr b))
        (cons '((car a) (car b)) c))))

现在以错误的情况考虑结果:

(defun zipper (a b)
  (if (= (OR (list-length a) (list-length b)) 0)
      nil
      (cons '((car a) (car b))
            (zipper (cdr a) (cdr b)))))

还有什么要做?

  • 请参阅'rsm'的注释:用对list的调用替换引号。
  • 不要使用list-length 请改用null 它检查列表是否为空。 list-length将遍历每次调用时输入的整个列表->低效率。

如果在递归的每个步骤调用list-length ,则每次将完全遍历两个列表,这将使zipper函数相对于列表大小的总和具有二次时间复杂度:

(zipper '(1 2 3) '(4 5 6))
=> (list-length (1 2 3))
=> (list-length (2 3))
=> (list-length (3))
=> (list-length ())

=> (list-length (4 5 6))
=> (list-length (4 5))
=> (list-length (5))
=> (list-length ())

(zipper '(2 3) '(5 6))
=> (list-length (2 3))
   ...
=> (list-length (5 6))
   ...

...

这是低效率的,在这里不是必需的。 由于您已经在访问两个列表,因此可以使用nullendp直接检查它们是否为空,这需要花费固定的时间。 列表之一为空时,您将立即返回NIL,这是mapcar的默认行为。 还要注意, mapcar可以同时处理多个列表,例如:

(mapcar #'+ '(1 2) '(5 8))
=> (6 10)

如果你知道一个函数,(至少)两个参数,并返回一个列表,那么你可以mapcar在你列出了功能,并有一个列表的列表。

mapcar是特例,其他语言(例如Python和Haskell)的zip函数。

传统的zip功能可以通过以下方式实现:

> (mapcar #'list list1 list2 ... listn)

这样在这种情况下:

> (mapcar #'list '(A B C D) '(1 2 3 4))
((A 1) (B 2) (C 3) (D 4))

要按照您的指示交换对的顺序,只需相应地更改传递给mapcar的函数:

> (mapcar #'(lambda (x y) (list y x)) '(A B C D) '(1 2 3 4))
((1 A) (2 B) (3 C) (4 D))

请查看mapcar文档以获取更多详细信息。

带有任意数量列表的zip函数

(defun zip (&rest lists)
  (apply #'mapcar #'list lists))

最短列表确定拉链的深度。

CL-USER> (zip '(1 2 3) '(a b c) '("a" "b" "c"))
((1 A "a") (2 B "b") (3 C "c"))
CL-USER> (zip '(1 2 3) '(a b c) '("a" "b" "c" "d"))
((1 A "a") (2 B "b") (3 C "c"))

您可以执行以下操作:

(defun zipper (a b)
   (if (or (null a) (null b))
       nil
       (cons (list (car b) (car a)) (our-combiner (cdr a) (cdr b)))))

我们可以检查其中一个列表是否为空,以便当其中一个列表用完时可以停止(类似于当一个列表用完时mapcar将停止对列表应用函数的方式)。 然后,我们可以在每个递归调用中将嵌套列表与列表中的汽车进行比较。 您的输出将是:

CL-USER> (zipper '(a b c d) '(1 2 3 4))
((1 A) (2 B) (3 C) (4 D))
CL-USER> 

我们还可以使用mapcar,因为它将遍历两个列表并返回将函数应用于两个列表的结果(与mapc不同)。 这是更少的代码行,并且由于它将在某些列表用完时返回,因此不需要有条件的:

(defun zipper (a b)
  (mapcar #'list b a))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM