如何编写带有两个列表并返回一个列表的scheme函数

时间:2014-03-13 09:56:11

标签: scheme plai

如何实现此功能

如果得到两个列表(a b c),(d e)

并返回列表(a + d b + d c + d a + e b + e c + e)

list元素全是整数,结果列表的元素顺序是免费的

我试过这个

(define (addlist L1 L2)
  (define l1 (length L1))
  (define l2 (length L2))
  (let ((result '()))
     (for ((i (in-range l1)))
        (for ((j (in-range l2)))
           (append result (list (+ (list-ref L1 i) (list-ref L2 j))))))))

但它返回错误,因为结果是'()

我不知道如何解决这个问题请帮帮我

5 个答案:

答案 0 :(得分:2)

数据转换方法:

   (a b c ...) (x y ...) 
1.  ==>  ( ((a x) (b x) (c x) ...)  ((a y) (b y) (c y) ...) ...)
2.  ==>  (  (a x) (b x) (c x) ...    (a y) (b y) (c y) ...  ...)
3.  ==>  (  (a+x) (b+x) ... )

(define (addlist L1 L2)
    (map (lambda (r) (apply + r))    ; 3. sum the pairs up
         (reduce append '()          ; 2. concatenate the lists
            (map (lambda (e2)        ; 1. pair-up the elements
                    (map (lambda (e1) 
                            (list e1 e2))  ; combine two elements with `list`
                         L1))
                 L2))))

测试(在MIT-Scheme中):

(addlist '(1 2 3) '(10 20))
;Value 23: (11 12 13 21 22 23)

你可以简化这个,所以没有单独的第3步吗?


我们可以在这里进一步分离出不同的比特和片段,如

(define (bind L f) (join (map f L)))
(define (join L) (reduce append '() L))
(define yield list)

然后,

(bind '(1 2 3) (lambda (x) (bind '(10 20) (lambda (y) (yield (+ x y))))))
;Value 13: (11 21 12 22 13 23)

(bind '(10 20) (lambda (x) (bind '(1 2 3) (lambda (y) (yield (+ x y))))))
;Value 14: (11 12 13 21 22 23)

答案 1 :(得分:1)

你走了:

(define (addlist L1 L2)
  (for*/list ((i (in-list L1)) (j (in-list L2)))
    (+ i j)))

> (addlist '(1 2 3) '(10 20))
'(11 21 12 22 13 23)

诀窍是使用for/list(或嵌套for*/list s时为for),它会自动为您执行append。另请注意,您可以遍历列表,无需使用索引。

要使结果“反过来”,反转L1和L2:

(define (addlist L1 L2)
  (for*/list ((i (in-list L2)) (j (in-list L1)))
    (+ i j)))

> (addlist '(1 2 3) '(10 20))
'(11 12 13 21 22 23)

答案 2 :(得分:1)

在方案中,不建议使用像set这样的功能!或追加! 因为它导致数据变化或变量,而不是功能编程风格。

应该这样:

(define (add-one-list val lst)
  (if (null? lst) '()
    (cons (list val (car lst)) (add-one-list val (cdr lst)))))

(define (add-list lst0 lst1)
  (if (null? lst0) '()
    (append (add-one-list (car lst0) lst1)
            (add-list (cdr lst0) lst1))))

首先理解函数add-one-list,它递归地调用自身,并且每次将lst的val和第一元素构建到列表中,并且CONS /将它作为最终答案累积。

add-list function就像add-one-list。

答案 3 :(得分:1)

(define (addlist L1 L2)
 (flatmap (lambda (x) (map (lambda (y) (+ x y)) L1)) L2))

(define (flatmap f L)
 (if (null? L)
     '()
     (append (f (car L)) (flatmap f (cdr L))))) 

1 ]=> (addlist '(1 2 3) '(10 20))

;Value 2: (11 12 13 21 22 23)

与Will和Procras一起参加此活动。如果您打算使用方案,不妨使用惯用方案。

使用for来构建列表对我来说有点奇怪。 (列表推导更适合)因为通常用于引起顺序副作用。那和RSR5没有定义for / list或for * / list。

Flatmap是一个相当常见的功能范例,您可以使用append而不是cons来构建列表以避免嵌套和空的子列表

答案 4 :(得分:0)

它不起作用,因为像append这样的函数不会改变容器。你可以使用像append!这样的变异函数来解决你的问题。通常,mutate函数的名称中包含!,如set!等。

但是如果不做突变就可以实现这一目标。您必须更改算法才能将结果发送到下一次迭代。像这样:

(let loop ((result '()))
   (loop (append result '(1)))

正如您所看到的,当循环被调用时,结果将是:

'()
'(1)
'(1 1)
'(1 1 1)
....

遵循此逻辑,您应该能够更改算法以使用此方法而不是for循环。您必须传递更多参数才能知道何时必须退出并返回result

我今天晚些时候会尝试添加更完整的答案。

这是append!的一个实现,我刚才写道:

(define (append! lst1 lst2)
  (if (null? (cdr lst1))
    (set-cdr! lst1 lst2)
    (append! (cdr lst1) lst2)))