[英]Using nested car with cons in a lisp function
I'm making a recursive lisp function that takes two lists and makes a sublist of index pairs 我正在做一个递归的Lisp函数,该函数需要两个列表并创建索引对的子列表
ex: put in (ABCD) and (1 2 3 4) and get ((1 A) (2 B) (3 C) (4 D)) 例如:放入(ABCD)和(1 2 3 4)并得到((1 A)(2 B)(3 C)(4 D))
However, I'm having trouble using car along with cons to make said sublist. 但是,我在使用汽车和缺点时难以进入所说的子列表。 Here's my code:
这是我的代码:
(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))
)
)
I played around for a little and it appears using car to create lists just doesn't work most of the time. 我玩了一会儿,似乎大部分时间都无法用汽车创建列表。 Additionally, I'm using CLISP.
另外,我正在使用CLISP。 Any ideas?
有任何想法吗?
Thanks! 谢谢!
The general idea goes into the right direction. 总体思路朝着正确的方向发展。 There are a bunch of problems, though.
但是,还有很多问题。 Let's have a look.
我们来看一下。
(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))
)
)
First indentation: 第一个缩进:
(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)) ; <--
)
)
Next dangling parentheses: 下一个悬挂的括号:
(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))))
Return the empty list in IF for the true case: 对于真实情况,请在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))))
Now cons to the result in the false case: 现在以错误的情况考虑结果:
(defun zipper (a b)
(if (= (OR (list-length a) (list-length b)) 0)
nil
(cons '((car a) (car b))
(zipper (cdr a) (cdr b)))))
What remains to be done? 还有什么要做?
list
. list
的调用替换引号。 list-length
. list-length
。 Use null
instead. null
。 It checks if a list is empty. list-length
would traverse the input whole lists on each call -> inefficient. list-length
将遍历每次调用时输入的整个列表->低效率。 If you call list-length
at each step of recursion, you are going to traverse both lists entirely each time, which gives your zipper
function a quadratic time complexity with respect to the sum of your lists' sizes: 如果在递归的每个步骤调用
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))
...
...
This is inefficient and not necessary here. 这是低效率的,在这里不是必需的。 Since you are already visiting both lists, you can directly check if any of them is empty using
null
or endp
, which take constant time. 由于您已经在访问两个列表,因此可以使用
null
或endp
直接检查它们是否为空,这需要花费固定的时间。 You return NIL as soon as one of the list is empty, which is by the way the default behaviour of mapcar
. 列表之一为空时,您将立即返回NIL,这是
mapcar
的默认行为。 Notice also that mapcar
can work on multiple lists at the same time, for example: 还要注意,
mapcar
可以同时处理多个列表,例如:
(mapcar #'+ '(1 2) '(5 8))
=> (6 10)
If you know a function that takes (at least) two arguments and return a list, then you could mapcar
that function over your lists and have a list of lists. 如果你知道一个函数,(至少)两个参数,并返回一个列表,那么你可以
mapcar
在你列出了功能,并有一个列表的列表。
The zip
function from other languages such as Python and Haskell is a special case of mapcar
. mapcar
是特例,其他语言(例如Python和Haskell)的zip
函数。
The traditional zip
function can be achieved via: 传统的
zip
功能可以通过以下方式实现:
> (mapcar #'list list1 list2 ... listn)
Such that for this case: 这样在这种情况下:
> (mapcar #'list '(A B C D) '(1 2 3 4))
((A 1) (B 2) (C 3) (D 4))
To swap the order of the pairs as you indicated, simply change the function passed to mapcar
accordingly: 要按照您的指示交换对的顺序,只需相应地更改传递给
mapcar
的函数:
> (mapcar #'(lambda (x y) (list y x)) '(A B C D) '(1 2 3 4))
((1 A) (2 B) (3 C) (4 D))
Checkout the documentation for mapcar for more details. 请查看mapcar文档以获取更多详细信息。
zip
function with arbitrary number of lists 带有任意数量列表的
zip
函数
(defun zip (&rest lists)
(apply #'mapcar #'list lists))
Shortest list determines depth of zipping. 最短列表确定拉链的深度。
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"))
You could do something such as this: 您可以执行以下操作:
(defun zipper (a b)
(if (or (null a) (null b))
nil
(cons (list (car b) (car a)) (our-combiner (cdr a) (cdr b)))))
We can check if either of the lists is null, so that we could stop when one of the lists runs out (similar to how mapcar will stop applying a function to lists when one of the lists runs out). 我们可以检查其中一个列表是否为空,以便当其中一个列表用完时可以停止(类似于当一个列表用完时mapcar将停止对列表应用函数的方式)。 We can then cons a nested list with the car's of the lists in each recursive call.
然后,我们可以在每个递归调用中将嵌套列表与列表中的汽车进行比较。 Your output would be:
您的输出将是:
CL-USER> (zipper '(a b c d) '(1 2 3 4))
((1 A) (2 B) (3 C) (4 D))
CL-USER>
We could also use mapcar as it will iterate over both lists and returns the result of applying the function to both lists (unlike mapc). 我们还可以使用mapcar,因为它将遍历两个列表并返回将函数应用于两个列表的结果(与mapc不同)。 This is fewer lines of code, and since it will return when some list runs out, there's no need for a conditional:
这是更少的代码行,并且由于它将在某些列表用完时返回,因此不需要有条件的:
(defun zipper (a b)
(mapcar #'list b a))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.