List 如何获取列表中某个位置的项的值?
我需要创建一个函数,用列表L中的Z替换所有出现的X和Y。我的问题是我的比较语句根据我的理解与位置本身进行比较 类似于在其他语言中循环时I值的工作方式?当我运行此代码时,它会替换位置3和位置7处的项目:List 如何获取列表中某个位置的项的值?,list,loops,lisp,common-lisp,List,Loops,Lisp,Common Lisp,我需要创建一个函数,用列表L中的Z替换所有出现的X和Y。我的问题是我的比较语句根据我的理解与位置本身进行比较 类似于在其他语言中循环时I值的工作方式?当我运行此代码时,它会替换位置3和位置7处的项目:(2 2 6 4 5 8 8 4)(2 2 7 6 4 5 7 5 8 4),而不是执行它应该执行的操作。所以我需要找出如何比较这个位置的值,而不是位置本身 如果我用print语句代替(replace)函数,它将打印26,所以我真的不明白这一点。我还尝试了(setf(nth Y Z)I)而不是具有相
(2 2 6 4 5 8 8 4)
(2 2 7 6 4 5 7 5 8 4)
,而不是执行它应该执行的操作。所以我需要找出如何比较这个位置的值,而不是位置本身
如果我用print语句代替(replace)函数,它将打印26
,所以我真的不明白这一点。我还尝试了(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) ))
我的问题是,我的比较陈述是根据我的理解与立场本身进行比较
当您执行(L中的i循环)
时,i
依次获取L中每个元素的值。您可以添加这样一个子句(p从0循环到L中的i)
来声明一个计数器p
,它表示列表中的当前位置
在replace
中,:start1
参数需要一个位置,因此您不想给它i
,而是p
,尽管这不是解决问题的最优雅的方法,当您在迭代过程中迭代L
时:对于只需要一次遍历L
的对象,这具有二次运行时间
顺便说一下,我不认为您应该在本练习中使用replace
。其要点是能够做到这一点(copy seq
是避免修改文字数据所必需的):
如果您想使用现有的标准函数,您可以使用;例如:
(defun replace-z (x y z l)
(let ((to-replace (list x y)))
(flet ((replacep (v) (member v to-replace)))
(substitute-if z #'replacep L))))
如果我用print语句代替(replace)函数,它将打印26,所以我真的不明白这一点
由此产生的代码将是:
(defun replace-z (X Y Z L)
(loop
for i in L
do (cond
((equal Y i) (print i))
((= X i) (print i))))
L)
请注意,最后的L
很难注意到(至少对我来说),通过使用循环中的现有结构,可能可以使返回值更明确一些:
(defun replace-z (X Y Z L)
(loop
for i in L
when (or (equal y i) (= x i))
do (print i)
finally (return L)))
当值x
或y
(请注意,=
和相等
的比较不同)时,您会打印值i
,这就是为什么您的输出是26
我也尝试过使用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) ))
不要对数字和字符使用eq
,因为允许实现对(eq x x)
返回NIL,否则这些值是eql
(例如,bignum整数)
我的问题是,我的比较陈述是根据我的理解与立场本身进行比较
当您执行(L中的i循环)
时,i
依次获取L中每个元素的值。您可以添加这样一个子句(p从0循环到L中的i)
来声明一个计数器p
,它表示列表中的当前位置
在replace
中,:start1
参数需要一个位置,因此您不想给它i
,而是p
,尽管这不是解决问题的最优雅的方法,当您在迭代过程中迭代L
时:对于只需要一次遍历L
的对象,这具有二次运行时间
顺便说一下,我不认为您应该在本练习中使用replace
。其要点是能够做到这一点(copy seq
是避免修改文字数据所必需的):
如果您想使用现有的标准函数,您可以使用;例如:
(defun replace-z (x y z l)
(let ((to-replace (list x y)))
(flet ((replacep (v) (member v to-replace)))
(substitute-if z #'replacep L))))
如果我用print语句代替(replace)函数,它将打印26,所以我真的不明白这一点
由此产生的代码将是:
(defun replace-z (X Y Z L)
(loop
for i in L
do (cond
((equal Y i) (print i))
((= X i) (print i))))
L)
请注意,最后的L
很难注意到(至少对我来说),通过使用循环中的现有结构,可能可以使返回值更明确一些:
(defun replace-z (X Y Z L)
(loop
for i in L
when (or (equal y i) (= x i))
do (print i)
finally (return L)))
当值x
或y
(请注意,=
和相等
的比较不同)时,您会打印值i
,这就是为什么您的输出是26
我也尝试过使用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) ))
不要将eq
用于数字和字符,因为允许实现将(eq x x)
返回NIL用于其他eql
(例如,bignum整数)的值。因为CL是一种工业强度语言,该语言已经提供了几个函数来执行类似的操作。然而,从学习Lisp的角度来看,最好考虑一下,如果不存在编写代码所需的算法,然后使用基本操作,而不是使用已经实现的函数之一来实际实现:这样做可以教你用Lisp编程,而查找和使用现有的工具会教你在手册中查找东西,这些是不同的技能
使用递归来解决这个问题
那么算法是什么呢
给定一个列表l
:
- 如果是空列表,我们就完成了李>
- 如果它不是空的,则将其拆分为第一个元素和其余元素李>
- 如果第一个元素为
X
或Y
,则结果为(cons'Z…
),否则为(cons…
,其中。
(defun replace-things-with-thing (l things thing &key (test #'eql))
(mapcar (lambda (e)
(if (member e things :test test)
thing
e))
l))
(defun memp (elt list &key (test #'eql))
(if (null list)
nil
(or (funcall test elt (first list))
(memp elt (rest list) :test #'eql))))
(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)))
(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))))))
(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 '())))
(substitute-if #\c (lambda (x) (member x '(#\a #\b))) "How about it?")
--> "How ccout it?"
(substitute-if 42 (lambda(x) (or (= x 0) (= x 1))) '(0 1 2 3 0 1))
--> (42 42 2 3 42 42)
(loop for x in '(0 1 2 3 0 1)
if (or (= x 0) (= x 1))
collect 42
else
collect x)
--> (42 42 2 3 42 42)
(loop with l = (list 0 1 2 3 0 1)
for c on l ; c means "cell"
for x = (car c)
if (or (= x 0) (= x 1)) do
(rplaca c 42)
finally (return l))
--> (42 42 2 3 42 42)