根据Racket Advanced Student中另一个列表的位置编号制作一个列表

时间:2015-11-08 12:00:50

标签: list scheme racket

我目前正在尝试编写一个函数,该函数为我提供了一个列表,其中包含元素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))

2 个答案:

答案 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. 使用自动缩进功能,它有助于使您的代码可读
  2. 为了理解此代码的工作原理,请使用内置调试程序逐步执行
  3. 阅读一个Scheme教程,它将教你常见的循环结构,以及其他有用的东西。

答案 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))

这有效,但它依赖于全局变量(llst),这不是一种非常好的做事方式。然后,您可以将其从全局变量转换为函数参数。可以通过将(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每次都是同一个列表,当你实际需要的部分每次缩小时。要解决此问题,您可以从前到后而不是从后面进行迭代,并在递归中使用firstrest。此外,必须切换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。