tags:

views:

190

answers:

5

Say I have:

(def s1 [1 2 3 4 5])
(def s2 [1 2 3 4 5])

For every x in s1, I want to multiply it with every y in s2.


To clarify, I basically want the Cartesian product, so I don't think map works here.

+9  A: 
(for [x1 s1
      x2 s2]
  (* x1 x2))
Michał Marczyk
It's... beautiful. *sheds a tear*
Blaine LaFreniere
I'm very new to Clojure, and functional programming in general, even though I know what that does... it still feels awkward and hard to wrap my head around it. Can you describe what's happening there?
Blaine LaFreniere
Firstly, you can type `(doc for)` at a Clojure REPL to get a (hopefully) good description of what `for` does; if you find it comes short of your expectations, your experience could help in improving the docstring! Secondly, here's a short summary: `for` takes a binding vector and a single "body" expression. The binding vector comprises names of locals (`x1` and `x2` in the above) and sequence-producing expressions (`s1` and `s2`). The body is evaluated once for each tuple of items in the Cartesian product of the seqs (here each (`x1`, `x2`) in the product of `s1` and `s2`).
Michał Marczyk
Fortunately, I did read the docs online for the for function, unfortunately it made my brain explode.
Blaine LaFreniere
The return value of `for` is a lazy sequence of results of evaluating the body for each of the tuples described above. The tuples can be filtered with `:when` and `:while` conditions and extra bindings can be introduced with `:let` inside the binding vector; see the docstring for details on these. (Also, re: your first comment: quite right, good sir! :-))
Michał Marczyk
See my answer for the java equivalent. Hopefully it helps you understand.
dbyrne
+3  A: 

Here is the java 1.5 (or newer) equivalent of Michal's code:

List<Integer> numbers = new ArrayList<Integer>();    

for(int x1 : s1) {
  for(int x2 : s2) {
    numbers.add(x1 * x2);
  }
}

The difference is that for loops in java don't return a sequence like they do in clojure, so you need to use a mutable ArrayList to construct the result.

Definitely not as pretty as the clojure version, but much better than what you would have had to do in Java 1.4.

dbyrne
+1  A: 

A simple, visual demonstration of the basic functionality of for:

user=> (pprint 
         (for [tens (range 10) 
               ones (range 10)]
           [tens ones]))
([0 0]
 [0 1]
 [0 2]
 [0 3]
 [0 4]
 [0 5]
 [0 6]
 [0 7]
 [0 8]
 [0 9]
 [1 0]
 [1 1]
 [1 2]
 [1 3]
 [1 4]
 [1 5]
 [1 6]
 [1 7]
 [1 8]
 [1 9]
 [2 0]
 [2 1]
 [2 2]
 [2 3]
 [2 4]
 [2 5]
 [2 6]
 [2 7]
 [2 8]
 [2 9]
 [3 0]
 [3 1]
 [3 2]
 [3 3]
 [3 4]
 [3 5]
 [3 6]
 [3 7]
 [3 8]
 [3 9]
 [4 0]
 [4 1]
 [4 2]
 [4 3]
 [4 4]
 [4 5]
 [4 6]
 [4 7]
 [4 8]
 [4 9]
 [5 0]
 [5 1]
 [5 2]
 [5 3]
 [5 4]
 [5 5]
 [5 6]
 [5 7]
 [5 8]
 [5 9]
 [6 0]
 [6 1]
 [6 2]
 [6 3]
 [6 4]
 [6 5]
 [6 6]
 [6 7]
 [6 8]
 [6 9]
 [7 0]
 [7 1]
 [7 2]
 [7 3]
 [7 4]
 [7 5]
 [7 6]
 [7 7]
 [7 8]
 [7 9]
 [8 0]
 [8 1]
 [8 2]
 [8 3]
 [8 4]
 [8 5]
 [8 6]
 [8 7]
 [8 8]
 [8 9]
 [9 0]
 [9 1]
 [9 2]
 [9 3]
 [9 4]
 [9 5]
 [9 6]
 [9 7]
 [9 8]
 [9 9])
Alex Taggart
+1  A: 

While solution using for is nicer, here is a map-only version if you have troubles understanding for:

(map #(map (partial * %) s2) s1)

for above expands to something similar, except it would use another anonymous function instead of partial, something like this:

(map (fn [x] (map (fn [y] (* x y)) s2)) s1)

or, neatly formated:

(map
  (fn [x]
    (map
      (fn [y]
        (* x y))
      s2))
  s1)
Dmitry Kakurin
Upvote for the alternative. I wonder if it's faster.
Blaine LaFreniere
BTW, to get behavior identical to **for** the first (outer) map should be replaced with mapcat.
Dmitry Kakurin
@Blaine See for yourself :-) :(use 'clojure.pprint)(set-pprint-dispatch code-dispatch)(pprint (macroexpand '(for [x1 s1 x2 s2] (* x1 x2))))
Dmitry Kakurin
A: 

As simple as it can get:

(map * '(1 2) '(3 4))

will yield:

(3 8)
Jawher
Mmh... not quite what I was looking for. It matches my English description, but I should have said from the start that I was looking for the Cartesian product of two sets. I just didn't know what it was called.
Blaine LaFreniere
Oops, indeed, I should have ready the answers more carefully.
Jawher