gpt4 book ai didi

list - 如何获取列表中某个位置项的值?

转载 作者:太空宇宙 更新时间:2023-11-03 18:49:19 24 4
gpt4 key购买 nike

我需要创建一个函数,用列表L中的Z替换所有出现的X和Y。我的问题是,我的compare语句与我所理解的位置本身进行比较。
类似于在其他语言中循环时I值的工作方式当我运行此代码时,它将替换位于位置3和位置7的项:(2 2 2 6 4 5 8 4 5 8 4)(2 2 7 6 4 5 7 4 5 8 4),而不是执行它应该执行的操作所以我需要找出如何比较那个位置的值,而不是位置本身。
如果我用print语句代替(replace)函数,它将打印2 2 2 6,所以我不太明白我还尝试了(setf (nth Y Z) i)而不是replace函数来获得相同的结果,这就是我如何找出compare语句的问题所在我也尝试过使用eq=equal来获得相同的结果。

 (defun replace-z (X Y Z L)


(loop for i in L
do
(cond

((equal Y i) (replace L (list Z) :start1 i))

((= X i) (replace L (list Z) :start1 i)))) L)
(trace replace-z)
(print (replace-z 2 6 7 '(2 2 2 6 4 5 8 4 5 8 4) ))

最佳答案

因为CL是一种工业级语言,所以它已经提供了一些功能来完成这样的事情然而,从学习LISP的角度来看,如果你想用它来写一些东西,如果它还不存在,那么你需要用什么算法来编写它,然后用基本操作来实现它,而不是使用已经完成的函数之一:这样做可以教你在Lisp编程,虽然找到和使用现有的工具教你看东西的手册,这些是不同的技能。
用递归法解决问题
那么算法是什么?
给出一个列表:
如果是空名单,我们就完了;
如果它不是空的,那么把它分成它的第一个元素和它的其余部分;
如果第一个元素是lX则结果是Y否则结果是(cons 'Z ...),其中(cons <existing first element> ...)表示“对列表的其余部分执行相同的过程”。
所以我们可以立即将其转换为代码:

(defun replace-x/y-with-z (l)
(if (null l)
l
(cons (if (or (eql (first l) 'x)
(eql (first l) 'y))
'z
(first l))
(replace-x/y-with-z (rest l)))))

好吧,这个函数在几个方面都很难看:其中之一是它经常调用 ...。我们可以通过绑定一个局部变量来处理这个问题我们也可以用 first替换毛茸茸的条件:
(defun replace-x/y-with-z (l)
(if (null l)
l
(let ((first (first l)))
(cons (case first
((x y) 'z)
(otherwise first))
(replace-x/y-with-z (rest l))))))

然后我们就可以得意忘形了,决定用 case来做这个将军:
(defun replace-things-with-thing (l things thing &key (test #'eql))
(if (null l)
l
(let ((first (first l)))
(cons (if (member first things :test test)
thing
first)
(replace-things-with-thing (rest l) things thing :test test)))))

所有这些都是为了避开房间里的大象:这些功能都不能正常工作它们不能正常工作,因为它们是递归的,并且在适当的时候它们将用完堆栈。
使用映射解决问题
如果我们想要这样一个函数在任何一致的CL中工作,我们需要以显式迭代的方式编写它们,或者使用CL保证的原语来处理非常长的列表为此,我们需要考虑一种不同的算法。算法如下:
给定定义的一个参数的函数 member,以便:
如果参数是 fX值是 Y
否则,值就是参数。
然后将此函数映射到列表上。
这就是 Z的作用所以现在:
(defun replace-x/y-with-z (l)
(mapcar (lambda (e)
(case e
((x y) 'z)
(otherwise e)))
l))

这是一个很好的易于理解的函数,它可以满足我们的需求。
我们可以再次概括如下:
(defun replace-things-with-thing (l things thing &key (test #'eql))
(mapcar (lambda (e)
(if (member e things :test test)
thing
e))
l))

这是一个很好的解决方案,我想:我最喜欢这个答案
一些更极端的方法
使用尾部递归
当然,如果我们使用一种语言,在语言层次上,它承诺将合适的递归过程转换为迭代过程,我们就可以编写这种语言的尾部递归版本,感觉非常聪明但事实上,我认为使用 mapcar的版本更好,因为这些东西的尾部递归版本将返回它们的结果,然后它们必须被反转但是,我们仍然可以编写一个很好的自然尾部递归函数,这将有助于: mapcar
元素是列表的成员,如果:
列表不是空的,并且
它(对于“equal”的某些定义)等于列表的头
或者是名单尾部的一员。
我们可以编写这个函数:
(defun memp (elt list &key (test #'eql))
(if (null list)
nil
(or (funcall test elt (first list))
(memp elt (rest list) :test #'eql))))

这个函数是tail递归的,因此任何消除tail调用的实现都会将其转换为迭代代码我们可以使用上面的函数而不是 member(注意,它返回的结果与 member返回的结果不同: member返回列表的尾部)。
最后,如果你想得到所有的幻想和担心性能,你可以写 member这样你就不必一直担心关键字参数&c,使用一个本地函数:
(defun memp (elt list &key (test #'eql))
(labels ((memp-loop (tail)
(if (null tail)
nil
(or (funcall test elt (first tail))
(memp-loop (rest tail))))))
(memp-loop list)))

这个成语在Scheme(一种消除尾部调用的语言)中非常常见,因此有特殊的语法(下面的代码是Racket):
(define (mem? elt lst #:test (test? eqv?))
(let mem-loop ([tail lst])
(if (null? tail)
#f
(or (test? elt (first tail))
(mem-loop (rest tail))))))

极端分子的做法
最后,让我们看看一种我称之为极端语言学习方法的方法:假设我们真的想实现我们自己完成这项工作所需的所有功能,只依赖语言提供的非常基本的工具特别是我们将允许自己使用这些设施:
假设语言将尾部调用转换为迭代;
带有 memp& cond的条件句(我们可以很容易地使用其中之一);
列出设施– ifnullfirstrest
相等测试– cons(作为参数提供);
eql因为CL是Lisp-2(Lisp-1中不需要);
使用 funcall的本地函数-我们可以全局定义所有的helper函数,但是最好将它们打包到一个函数中。
此外,对于顶级函数,我们将使用一次奇特的参数处理。
我们不允许使用任何映射列表的函数,或类似的任何函数:所有我们需要编写的函数。
有了这些限制,我们最终会遇到这样的恐怖:
(defun replace-things-with-thing (l things thing &key (test #'eql))
;; an absurdly purist, tail recursive version
(labels ((memp (e tail)
;; is E in TAIL compared using TEST. In real life this
;; would be MEMBER
(cond ((null tail)
nil)
((funcall test e (first tail))
t)
(t (memp e (rest tail)))))
(rev (tail accum)
;; reverse TAIL. In real life this would be REVERSE
(if (null tail)
accum
(rev (rest tail) (cons (first tail) accum))))
(replace-loop (tail accum)
;; the implementation of the function
(if (null tail)
;; we're done: the reverse of ACCUM is the answer
(rev accum '())
(let ((e (first tail)))
(replace-loop (rest tail)
(cons (if (memp e things)
thing
e)
accum))))))
(replace-loop l '())))

我想你可以说写这样的东西有助于你学习口齿不清但我不确定这是真的。
(当然,你可以更进一步:真正的纯粹主义者会在这里使用Y组合词,如果你认为这有助于你学习语言的话,好吧。)

关于list - 如何获取列表中某个位置项的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57900678/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com