在迭代期间从条件创建列表

时间:2013-10-18 21:52:54

标签: scheme

我写了一个简单的程序来查找数字的除数(不包括数字本身)。我已经想出了如何打印它们,但是我想让这个函数返回一个包含每个除数的列表。

(define (divisors n)

  (do ((i 1 (+ i 1)))    
    ((> i (floor (/ n 2))))
    (cond 
      ((= (modulo n i) 0)
       (printf "~a " i)))))

我的想法是创建一个本地列表,向我的printf表达式添加元素,然后让函数返回该列表。我该怎么做呢?我是Scheme的新手,也是Lisp的新手。

2 个答案:

答案 0 :(得分:1)

您是否必须使用必须使用do?这是一种方式:

(define (divisors n)
  (do ((i 1 (add1 i))
       (acc '() (if (zero? (modulo n i)) (cons i acc) acc)))
    ((> i (floor (/ n 2)))
     (reverse acc))))

但我相信如果您使用named let构建输出列表会更容易理解:

(define (divisors n)
  (let loop ((i 1))
    (cond ((> i (floor (/ n 2))) '())
          ((zero? (modulo n i))
           (cons i (loop (add1 i))))
          (else (loop (add1 i))))))

或者,如果您正好使用Racket,可以使用for/fold,如下所示:

(define (divisors n)
  (reverse
   (for/fold ([acc '()])
     ([i (in-range 1 (add1 (floor (/ n 2))))])
     (if (zero? (modulo n i))
         (cons i acc)
         acc))))

请注意,所有上述解决方案都是以函数式编程风格编写的,这是在Scheme中编程的惯用方法 - 不使用变异操作。也可以编写一个程序式的解决方案(参见@ GoZoner的回答),类似于你用C语言解决这个问题的方法,但这不是惯用的

答案 1 :(得分:1)

只需创建一个局部变量l并扩展它而不是打印东西。完成后,返回它。像这样:

(define (divisors n)
  (let ((l '()))
    (do ((i 1 (+ i 1)))    
        ((> i (floor (/ n 2))))
      (cond ((= (modulo n i) 0)
             (set! l (cons i l))))
    l))

请注意,因为i的前面l被“强制”,所以l中的排序会从高到低。如果需要从低到高的顺序,请使用(reverse l)作为返回值。