0

how to implement this function

if get two list (a b c), (d e)

and return list (a+d b+d c+d a+e b+e c+e)

list element is all integer and result list's element order is free

I tried this like

(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))))))))

but it return error because result is '()

I don't know how to solve this problem please help me

user77292
  • 3
  • 2

5 Answers5

2

A data-transformational approach:

   (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))))

testing (in MIT-Scheme):

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

Can you simplify this so there's no separate step #3?


We can further separate out the different bits and pieces in play here, as

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

then,

(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)
Will Ness
  • 70,110
  • 9
  • 98
  • 181
1

Here you go:

(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)

The trick is to use for/list (or for*/list in case of nested fors) , which will automatically do the append for you. Also, note that you can just iterate over the lists, no need to work with indexes.

To get the result "the other way round", invert L1 and 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)
uselpa
  • 18,732
  • 2
  • 34
  • 52
1

In scheme, it's not recommended using function like set! or append!. because it cause data changed or Variable, not as Funcitonal Programming Style.

should like this:

(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))))

first understanding function add-one-list, it recursively call itself, and every time build val and fist element of lst to a list, and CONS/accumulate it as final answer.

add-list function just like add-one-list.

liuyang1
  • 1,575
  • 1
  • 15
  • 23
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)

Going with Will and Procras on this one. If you're going to use scheme, might as well use idiomatic scheme.

Using for to build a list is a bit weird to me. (list comprehensions would fit better) For is usually used to induce sequential side effects. That and RSR5 does not define a for/list or for*/list.

Flatmap is a fairly common functional paradigm where you use append instead of cons to build a list to avoid nested and empty sublists

WorBlux
  • 1,423
  • 11
  • 20
  • There's nothing weird about using `for` here, it is actually idiomatic Racket (what the OP is obviously using). Also, it's the only solution without `append`. – uselpa Mar 13 '14 at 18:03
0

It doesn't work because functions like append don't mutate the containers. You could fix your problem with a mutating function like append!. Usually functions that mutate have a ! in their name like set! etc.

But it's possible to achieve that without doing mutation. You'd have to change your algorithm to send the result to your next iteration. Like this:

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

As you can see, when loop will get called, result will be:

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

Following this logic you should be able to change your algorithm to use this method instead of for loop. You'll have to pass some more parameters to know when you have to exit and return result.

I'll try to add a more complete answer later today.

Here's an implementation of append! I just wrote:

(define (append! lst1 lst2)
  (if (null? (cdr lst1))
    (set-cdr! lst1 lst2)
    (append! (cdr lst1) lst2)))
Loïc Faure-Lacroix
  • 13,220
  • 6
  • 67
  • 99
  • thank you for answer! but it returns "append! is unbound identifier" I don't know why should i implement something? ah, my language is plai – user77292 Mar 13 '14 at 10:05
  • Yeah `append!` isn't always present. I know there is also `list-append!` that does the same thing... check for the docs if it's available. If it doesn't exists you can implement it with `set-cdr!`. – Loïc Faure-Lacroix Mar 13 '14 at 10:07
  • if `null?` doesn't exists, you can use `(= (cdr lst1) '())` in theory. – Loïc Faure-Lacroix Mar 13 '14 at 10:12