是否有更短/更好的方式来编写以下内容? 可能有一些库进行转换,但我想知道是否有某种 地图或折叠可行吗?
(define (weights-to-range lw)
; '(1 4 6 6 6 6 6) -> (1 5 11 17 23 29 35)
(define (f x lw acc)
(if (null? lw)
acc
(let ([y (+ x (car lw))])
(f y (cdr lw) (append acc (list y))))))
(f (car lw) (cdr lw) (list (car lw))))
答案 0 :(得分:3)
在Racket中,我可能会使用for/fold
列表理解来编写它:
(define (weights-to-range weights)
(define-values (xs _)
(for/fold ([xs '()] [prev 0])
([weight (in-list weights)])
(define this (+ prev weight))
(values (cons this xs) this)))
(reverse xs))
(require rackunit)
(check-equal? (weights-to-range '(1 4 6 6 6 6 6))
'(1 5 11 17 23 29 35))
除此之外,它会更简单,因为这会为fold/fold
- xs
和prev
提供两个累积值 - for/fold
形式将返回两个值。所以我们需要使用define-values
将两者都塞进临时变量中,然后再将我们关注的变量从xs
- 传递到reverse
。 (prev
的var名为_
。这只是一个含义为“忽略”的约定,因为我们不需要它。)
当然,这里的一般想法是使用对的“滑动窗口”“折叠”列表,累积结果到目前为止每个步骤都可用。在您的情况下,函数是+
,但可以推广:
(define (fold-slide f vs)
(define-values (xs _)
(for/fold ([xs '()] [prev 0])
([v (in-list vs)])
(define this (f prev v))
(values (cons this xs) this)))
(reverse xs))
使用这样的fold-slide
(缺少一个更好的名字)功能,你可以简单地写一下:
(fold-slide + '(1 4 6 6 6 6 6)
如果它可以处理任何大小的“窗口”,而不仅仅是2,那么fold-slide
可能会更有用。
P.S。完全有可能有一些SRFI做这样的事情,或者更优雅的方式在Racket中做,我不知道。
答案 1 :(得分:2)
在仍然直接建立答案的同时拥有一个累加器是完全没问题的(也就是说,而不是累积一个反向的答案,然后在结束时将其反转)。
;; weights-to-range : (listof number) -> (listof number)
;; Returns list of partial sums of input list.
(define (weights-to-range lw0)
;; helper : (listof number) number -> (listof number)
;; acc is the sum of elements seen so far
(define (helper lw acc)
(cond [(null? lw)
null]
[else
(let ([new-acc (+ acc (car lw))])
(cons new-acc (helper (cdr lw) new-acc)))]))
(helper lw0 0))