如何在不使用递归的情况下将数字列表转换为Racket中的单独实体?
例如,我想将(列出1 2 3 4)转换为单独的1 2 3 4数字,因此我可以将所有实体添加到一起,给我1 + 2 + 3 + 4 = 10。
答案 0 :(得分:2)
“将列表分解为单独的实体”并没有真正使有那么多意义,因为这些数字必须存储在某处。编写定义时,将值绑定到名称,如下所示:
(define x 7)
但是当你有一个列表时,你有多个值,所以为了将列表分成单个部分,你需要多个名字。如果您的列表长度始终相同,则这不是不可能的 - 您可以使用first
,second
,third
等功能来提取单个值:
(define lst '(1 2 3))
(define a (first lst))
(define b (second lst))
(define c (third lst))
但是,列表通常不会以这种方式使用,并且在大多数情况下,列表可以是任意长度。因此,不可能知道提前给出值的名称,因为编写程序时所需的名称数量不一定是已知的!因此,您不希望“打破列表”,您 想要做的事情是立即对整个列表进行操作。
同时对整个列表进行操作的最原始的方法是显式使用递归,但大多数时候,有递归模式经常出现,有现有的函数要做没有编写所有样板的同样的事情。例如,map
将函数应用于列表的每个元素,filter
从列表中选择满足谓词的元素。但是,对于您的问题,您不需要这些内容:您希望一起收集列表的所有元素以生成单个值。
函数式编程中“收集元素”的概念称为 fold ,而Racket提供foldl
(“左侧折叠”)函数来做到这一点。您提供了一个函数,在您的情况下+
收集一个“零值”,它将用作起始累加器,以及要收集的列表。在这种情况下,“零值”只是数字0
,因为零是附加标识:
(define (sum lst)
(foldl + 0 lst))
> (sum '(1 2 3))
6
折叠是收集列表元素的一种非常通用的方式。但是,正如Alex Knauth提到的那样,Scheme为更简单的情况提供了另一种方法:因为Scheme中的+
可以接受任意数量的参数,如果你提供两个以上的数字,它会隐式地进行折叠:< / p>
> (+ 1 2 3)
6
要使用一组参数作为列表而不是单独的值来调用函数,可以使用apply
,它接受函数和列表作为参数:
(define (sum lst)
(apply + lst))
这是在Scheme和Racket中执行数字列表的简单求和的惯用方法。
答案 1 :(得分:1)
你想要的是apply
:
> (apply + (list 1 2 3 4))
10
你有一个函数+
,它接受多个参数(不是作为列表,而是作为单独的参数)。您希望将此函数应用于列表的元素,列表的每个元素都是要传入的单独参数。这正是apply
的作用。
apply
调用
(apply + (list 1 2 3 4))
相当于
(+ 1 2 3 4)
apply
的主要优势在于它适用于计算列表,而不仅仅是硬编码的(list ...)
表单,因此它也适用于append
个列表:
> (apply + (append (list 1 2 3 4) (list 2 3 4)))
19
来自函数参数的列表,如Alexis King's answer所述:
> (define (sum lst)
(apply + lst))
> (sum (list 1 2 3 4))
10
> (sum (append (list 1 2 3 4) (list 2 3 4)))
19
答案 2 :(得分:0)
将数字列表转换为它的独立实体。如果您知道长度可以使用访问者:
(define lst '(1 2 3 4))
(+ (first lst) (second lst) (third lst) (fourth lst)) ; ==> 10
first
,second
,...位于racket/list
和#!racket
语言中。它们是更通用的cxr访问器的别名:
(+ (car lst) (cadr lst) (caddr lst) (cadddr lst)) ; ==> 10
如果你有一个列表lst
,你知道它是合理的,少于200个元素,你可以使用apply
将它们全部作为参数提供,甚至可以在前面提供额外的参数:
(apply + lst) ; ==> 10
(apply + 5 lst) ; ==> 15
rest参数和apply之间存在对称性,因此有人可能将它们视为对话:
(define (prefix-zero . xs)
(apply list 0 xs))
(prefix-zero 1 2 3) ; ==> (0 1 2 3)
对于较大的列表,您可以使用foldl
,将第二个参数作为中间值,使用两个和两个到一个值:
(foldl + 0 lst) ; ==> 10
foldl
是使用递归实现的,它以+从0开始,每个元素都起作用:
(+ (cadddr lst) (+ (caddr lst) (+ (cadr lst) (+ 0 (car lst))))) ; ==> 10
答案 3 :(得分:-1)
我相信你也可能对quasiquote函数感兴趣。
用途更加通用,但是展示其运作方式的一个例子:
如果有列表,请说
(define list1 (list 5 6 7))
然后你可以创建另一个列表:
(define list2 `(1 2 3 4 ,@list1))
(define list3 `(1 2 3 4 ,list1))
或
(define list2 (quasiquote (1 2 3 4 (unquote-splicing list1))))
(define list3 (quasiquote (1 2 3 4 (unquote list1))))
> list2
'(1 2 3 4 5 6 7)
> list3
'(1 2 3 4 (5 6 7))