列表中的成员-LISP
我需要用Lisp编写一个程序来查看列表中特定字符的出现次数。例如,下列列表中出现的1[1,2,3,1,1]Lisp中的列表是cons节点序列:成对的指针-第一个指向有效负载数据,第二个指向列表的其余部分。例如,对于列表中的成员-LISP,lisp,Lisp,我需要用Lisp编写一个程序来查看列表中特定字符的出现次数。例如,下列列表中出现的1[1,2,3,1,1]Lisp中的列表是cons节点序列:成对的指针-第一个指向有效负载数据,第二个指向列表的其余部分。例如,对于[1,2,3,1,1] . / \ 1 . / \ 2 . / \ 3 ...... . / \ 1 NIL
[1,2,3,1,1]
.
/ \
1 .
/ \
2 .
/ \
3 ...... .
/ \
1 NIL
NIL
是一个表示空列表的特殊值,这样系统就知道不再尝试进一步研究它。在计划中
(define NIL '())
(define (myfold f z list)
(cond
((null? list) z) ; replace NIL with the initial ("zero") value
(else
(f ; combine
(car list) ; the payload datum, and the delayed,
(lambda () ; by creating a function to calculate it,
(myfold f z ; result of recursively folding
(cdr list))))))) ; the rest of list
递归列表处理范式由以下概念捕获:每个节点用二进制函数“替换”,特殊节点用一些特殊的“零”值替换(f1(f2(f 3(…(f 1 z)…)。在方案中
(define NIL '())
(define (myfold f z list)
(cond
((null? list) z) ; replace NIL with the initial ("zero") value
(else
(f ; combine
(car list) ; the payload datum, and the delayed,
(lambda () ; by creating a function to calculate it,
(myfold f z ; result of recursively folding
(cdr list))))))) ; the rest of list
这样,组合函数f
必须处理两个值:一个是节点的有效负载数据,另一个是递归折叠的(延迟)结果,具有相同的f
和z
,该节点之后的列表的其余部分
(define (keep-equals v list)
(myfold
(lambda (a r) ; combine ...
(if (equal? v a)
(cons a ... ) ; the same thing goes over the dots, here
... )) ; and here
'() ; replace the NIL of the argument list with this
list))
由于递归折叠结果的计算是通过创建一个函数来延迟的,在需要结果时调用该函数,因此我们需要在确实需要这些结果时通过调用该函数来“强制”执行该计算
如果你想计算出现的次数而不是在列表中收集它们,你只需要使用不同的组合函数和不同的初始(“零”)值
特别是,我们通过cons
将一个值添加到列表的其余部分(以NIL作为初始值,空列表)来构建一个列表;而我们通过递增一个计数器(以0作为该计数器的初始值)来计数
例如,通过折叠计算一个列表的长度,我们基本上把它的每个元素都转换成1:
length[a,b,c,d,e]==1+(1+(1+(1+(1+0)))
。在这里,组合函数将需要有条件地增加计数器,仅当有效负载数据达到我们想要计数的程度时。Lisp中的列表是一系列cons节点:成对的指针-第一个指向有效负载数据,第二个指向列表的其余部分。例如,对于[1,2,3,1,1]
.
/ \
1 .
/ \
2 .
/ \
3 ...... .
/ \
1 NIL
NIL
是一个表示空列表的特殊值,这样系统就知道不再尝试进一步探索它。在Scheme中
(define NIL '())
(define (myfold f z list)
(cond
((null? list) z) ; replace NIL with the initial ("zero") value
(else
(f ; combine
(car list) ; the payload datum, and the delayed,
(lambda () ; by creating a function to calculate it,
(myfold f z ; result of recursively folding
(cdr list))))))) ; the rest of list
递归列表处理范式由以下概念捕获:每个节点用二进制函数“替换”,特殊节点用一些特殊的“零”值替换(f1(f2(f 3(…(f 1 z)…)。在方案中
(define NIL '())
(define (myfold f z list)
(cond
((null? list) z) ; replace NIL with the initial ("zero") value
(else
(f ; combine
(car list) ; the payload datum, and the delayed,
(lambda () ; by creating a function to calculate it,
(myfold f z ; result of recursively folding
(cdr list))))))) ; the rest of list
这样,组合函数f
必须处理两个值:一个是节点的有效负载数据,另一个是递归折叠的(延迟)结果,具有相同的f
和z
,该节点之后的列表的其余部分
(define (keep-equals v list)
(myfold
(lambda (a r) ; combine ...
(if (equal? v a)
(cons a ... ) ; the same thing goes over the dots, here
... )) ; and here
'() ; replace the NIL of the argument list with this
list))
由于递归折叠结果的计算是通过创建一个函数来延迟的,在需要结果时调用该函数,因此我们需要在确实需要这些结果时通过调用该函数来“强制”执行该计算
如果你想计算出现的次数而不是在列表中收集它们,你只需要使用不同的组合函数和不同的初始(“零”)值
特别是,我们通过cons
将一个值添加到列表的其余部分(以NIL作为初始值,空列表)来构建一个列表;而我们通过递增一个计数器(以0作为该计数器的初始值)来计数
例如,通过折叠计算一个列表的长度,我们基本上把它的每个元素都转换成1:
length[a,b,c,d,e]==1+(1+(1+(1+(1+0)))
。在这里,组合函数将需要有条件地增加计数器,仅当有效负载数据达到我们想要计算它们的程度时。我自己是lisp新手,但我会这样做。我还没有看过will给出的其他答案,所以我会在发布后检查。成员
函数具有uti告诉您它是否在列表中找到了某些内容,并从发现位置开始返回该列表的其余部分:
CL-USER> (member '1 '(0 1 2 3))
(1 2 3)
然后,您可以递归调用使用成员的函数,并从let
中的变量中的返回值递增计数器:
(defun find1 (alist)
(let ((count 0))
(labels ((findit (list)
(let ((part (member '1 list)))
(if part
(progn (incf count)
(findit (rest part)))
0))
count))
(findit alist))))
结果如下:
CL-USER> (find1 '(1 2 3 4 5))
1
CL-USER> (find1 '(1 1 2 3 4 5))
2
CL-USER> (find1 '(1 1 1 2 3 1 4 5 1 1))
6
通过使用cond
而不是if
更新:根据评论,这里是上述内容的更新版和更优雅的版本,我认为也可以称之为尾部递归:
(defun find1 (alist &optional (accum 0))
(let ((part (member '1 alist)))
(if part
(find1 (rest part) (+ accum 1))
accum)))
这就是它的作用:
CL-USER> (find1 '(1 2 3 4))
1
CL-USER> (find1 '(1 1 1 1))
4
CL-USER> (find1 '(1 1 0 1 1))
4
CL-USER> (find1 '(0 2 1 0 1 1 0 1 1))
5
我自己对lisp还不熟悉,但我会这样做。我还没有看过Will的其他答案,所以我会在发布后检查。member
函数既可以告诉您它是否在列表中找到了某个内容,也可以从找到该内容的位置返回该列表的其余部分:
CL-USER> (member '1 '(0 1 2 3))
(1 2 3)
然后,您可以递归调用使用成员的函数,并从let
中的变量中的返回值递增计数器:
(defun find1 (alist)
(let ((count 0))
(labels ((findit (list)
(let ((part (member '1 list)))
(if part
(progn (incf count)
(findit (rest part)))
0))
count))
(findit alist))))
结果如下:
CL-USER> (find1 '(1 2 3 4 5))
1
CL-USER> (find1 '(1 1 2 3 4 5))
2
CL-USER> (find1 '(1 1 1 2 3 1 4 5 1 1))
6
通过使用cond
而不是if
更新:根据评论,这里是上述内容的更新版和更优雅的版本,我认为也可以称之为尾部递归:
(defun find1 (alist &optional (accum 0))
(let ((part (member '1 alist)))
(if part
(find1 (rest part) (+ accum 1))
accum)))
这就是它的作用:
CL-USER> (find1 '(1 2 3 4))
1
CL-USER> (find1 '(1 1 1 1))
4
CL-USER> (find1 '(1 1 0 1 1))
4
CL-USER> (find1 '(0 2 1 0 1 1 0 1 1))
5
我很喜欢这个问题的答案。但看起来它们都比必要的工作量要多。另一方面,考虑到每个人的想法,我很高兴