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

时间:2019-02-11 03:53:36

标签: list lisp common-lisp clisp cons

我正在制作一个递归lisp函数,该函数接受两个列表并创建一个索引对的子列表

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

但是,我在使用car和cons进入子列表时遇到了麻烦。这是我的代码:

(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。有什么想法吗?

谢谢!

5 个答案:

答案 0 :(得分:5)

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

countries = forms.MultipleChoiceField(choices=COUNTRIES, widget=forms.CheckboxSelectMultiple)

第一个缩进:

(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)
      (setq c NIL)
      (progn (zipper (cdr a) (cdr b))
        (cons '((car a) (car b)) c))))

现在在 false 情况下使用结果:

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

还有什么要做?

  • 通过“ rsm”查看评论:用对(defun zipper (a b) (if (= (OR (list-length a) (list-length b)) 0) nil (cons '((car a) (car b)) (zipper (cdr a) (cdr b))))) 的调用代替引号。
  • 请勿使用list。请改用list-length。它检查列表是否为空。 null将遍历每次呼叫的输入整个列表->低效。

答案 1 :(得分:3)

如果您在递归的每一步调用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使用该函数,并获得一个列表列表。

答案 2 :(得分:3)

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

传统的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))

检出documentation for mapcar以获得更多详细信息。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

您可以执行以下操作:

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