Multiplying each element of a list with each element of another list in Scheme programming

Tag: list , recursion , scheme , racket , multiplication Author: wangzhnju Date: 2011-11-11

i am trying to do the following in Scheme:

List<int> list = new List<int>();
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list1.Add(2);
list1.Add(4);
list1.Add(6);
list1.Add(8);

for (int i = 0; i < list.Count; i++)
{
    for (int p = 0; p < list1.Count; p++)
    {
         list2.Add(list[i] * list1[p]);
    }
}

as seen in the code above, I am trying to multiply each element of the first list with every element in the second list. So 1*2, 1*4, 1*6, 1*8, then going to the next element, 2*2,2*4.. etc.

I am having trouble implementing this into Scheme. I tried using the map function but this doesn't seem to work the way I want it to. Any ideas?

How did you try it with map and how did it not work like you want? If your only problem is that the result was in nested lists, you could just flatten it afterwards.

Best Answer

We start by defining the two input lists, I renamed them since list is a built-in procedure in Scheme and is not a good idea to overwrite it):

(define l '(1 2 3 4))
(define l1 '(2 4 6 8))

I'm assuming that you want your result list to be "flat" - e.g., it doesn't contain lists of elements, only elements (if you're ok with having a list of lists in l2, simply delete the call to flatten below). For that, we need to define the flatten procedure:

(define (atom? x)
  (and (not (pair? x)) (not (null? x))))

(define (flatten lst)
  (cond ((null? lst) empty)
        ((atom? lst) (list lst))
        (else (append (flatten (car lst))
                      (flatten (cdr lst))))))

Finally, the problem at hand. It's simple once you understand how to nest two map procedures - take a look at the nested mappings section in the book SICP.

(define l2
  (flatten
   (map (lambda (i)
          (map (lambda (j)
                 (* i j))
               l1))
        l)))

At this point, l2 contains the expected answer:

(2 4 6 8 4 8 12 16 6 12 18 24 8 16 24 32)

comments:

thanks alot, it works now!
Good! how about an accepted answer? :)
i have no idea how to do that?else i would lol
For every answer, to its left there's a check (below the down arrow, under the number 2). It's customary to accept an useful answer by clicking in that check, that marks the answer as correct.

Other Answer1

Óscar has given a very complete answer to this question, but I wanted to add two minor notes:

The Scheme dialect Racket has a nice built-in form called for*/list which does exactly this sort of thing:

(for*/list ([i '(1 2 3 4)]
            [j '(2 4 6 8)])
  (* i j))

Also, instead of using your own or the library's flatten function in the nested-maps solution, you could replace the outer map with append-map from SRFI-1. There are plenty of other ways too, of course ;-)

comments:

thank you, works too!

Other Answer2

I can't believe nobody has given the most straightforward answer: nested uses of map:

(append-map (lambda (x)
              (map (lambda (y) (* x y))
                   (list 2 4 8 6)))
            (list 1 2 3 4))

append-map is a simple variant of map that assumes that the mapping function returns a list, so it concatenates all the result lists. This is a library function in most serious Scheme systems (it's in the SRFI-1 library), but here's a simple, incomplete definition (a complete definition would handle multiple argument lists):

(define (append-map f xs)
  (concat (map f xs)))

;;;
;;; Turns a list of lists into a list by appending all the top-level sublists.
;;; This is also a common library function.
;;;
(define (concat lists)
  (if (null? lists)
      '()
      (append (car lists)
              (concat (cdr lists)))))