我目前正在尝试编写一个函数,该函数为我提供了一个列表,其中包含元素1作为元素的位置的位置编号。
不幸的是,当我执行以下函数时,它会给我'()
这是lst
的初始值。
所以我不确定要为案例(< pos 0)
写些什么。
(define lst '())
(define (posj pos) (if (< pos 0)
lst
(begin (cond ((equal? (list-ref l pos) 1) (begin (set! lst (append (list* pos) '()))
(posj (- pos 1))))
(else (posj (- pos 1)))))))
(define l '(1 3 1 2 1 5 1))
(posj (- (length l) 1))
答案 0 :(得分:1)
您的代码不起作用(追加只需要列表),并且由于多种原因,不能在Scheme中执行此操作。
我建议使用named let(经典方案):
(define (posj lst val)
(let loop ((lst lst) (pos 0) (res null))
(if (null? lst)
(reverse res)
(loop (cdr lst)
(add1 pos)
(if (= (car lst) val) (cons pos res) res)))))
或更“机架”
(define (posj lst val)
(reverse
(for/fold ((res null)) (((elt pos) (in-indexed lst)))
(if (= elt val) (cons pos res) res))))
然后
> (posj '(1 3 1 2 1 5 1) 1)
'(0 2 4 6)
由于您正在使用Racket,可能是Dr Racket(IDE),
答案 1 :(得分:1)
你可能想写的是list
而不是list*
,lst
而不是'()
:(以及更多的标准缩进)
(define lst '())
(define (posj pos)
(if (< pos 0)
lst
(cond [(equal? (list-ref l pos) 1)
(begin
(set! lst (append (list pos) lst))
(posj (- pos 1)))]
[else
(posj (- pos 1))])))
(define l '(1 3 1 2 1 5 1))
(posj (- (length l) 1))
这有效,但它依赖于全局变量(l
和lst
),这不是一种非常好的做事方式。然后,您可以将其从全局变量转换为函数参数。可以通过将(set! lst (append ...))
作为参数传递来替换(append ...)
:
(define (posj l lst pos)
(if (< pos 0)
lst
(cond [(equal? (list-ref l pos) 1)
(posj l (append (list pos) lst) (- pos 1))]
[else
(posj l lst (- pos 1))])))
(define l '(1 3 1 2 1 5 1))
(posj l '() (- (length l) 1))
到目前为止l
每次都是同一个列表,当你实际需要的部分每次缩小时。要解决此问题,您可以从前到后而不是从后面进行迭代,并在递归中使用first
和rest
。此外,必须切换append
参数的顺序,因为我们现在正在向另一个方向迭代,(< pos 0)
检查可以用(empty? l)
检查替换:
(define (posj l lst pos)
(if (empty? l)
lst
(cond [(equal? (first l) 1)
(posj (rest l) (append lst (list pos)) (+ pos 1))]
[else
(posj (rest l) lst (+ pos 1))])))
(define l '(1 3 1 2 1 5 1))
(posj l '() 0)
现在,如果您可以使用append
而不是使用cons
,那么效率会更高。这会反转lst
,因此将其重命名为rev-lst
,当您将其重新命名时,请将其反转:
(define (posj l rev-lst pos)
(if (empty? l)
(reverse rev-lst)
(cond [(equal? (first l) 1)
(posj (rest l) (cons pos rev-lst) (+ pos 1))]
[else
(posj (rest l) rev-lst (+ pos 1))])))
(define l '(1 3 1 2 1 5 1))
(posj l '() 0)
现在它开始看起来很像列表函数的模板,特别是如果用if
替换cond
。此外,如果您想避免将'()
和0
作为额外参数传递,则可以使用辅助函数或命名let。