8
votes

Suppose I've got:

'[[c c c]
  [y y y]
  [m m m]]

and

'[[r g b]
  [r g b]
  [r g b]]

and I'd like to have:

'[[[c,r] [c,g] [c,b]]
  [[y,r] [y,g] [y,b]]
  [[m,r] [m,g] [m,b]]]

What is the elegant way to do this in clojure?

4

4 Answers

8
votes
(def a '[[c c c]
         [y y y]
         [m m m]])
(def b '[[r g b]
         [r g b]
         [r g b]])

(mapv (partial mapv vector) a b) ;; will work with arbitrary number 
                                 ;; of equal sized arguments

;=> [[[c r] [c g] [c b]] [[y r] [y g] [y b]] [[m r] [m g] [m b]]]
4
votes

Consider adopting core.matrix for stuff like this.

It will manipulate nested vectors as matrices quite happily, but also does much more powerful stuff if you need it (for example, support for accelerated native matrix libraries via JBLAS). It's shaping up to be the definitive library/API for matrix computations in Clojure.

In this case you can simply use "emap" to apply a function element-wise to two matrices:

(use 'core.matrix)

(def cym '[[c c c]
           [y y y]
           [m m m]])

(def rgb '[[r g b]
           [r g b]
           [r g b]])

(emap vector cym rgb)

=> [[[c r] [c g] [c b]] 
    [[y r] [y g] [y b]] 
    [[m r] [m g] [m b]]]
3
votes

partition and interleave get you there, as seqs:

(def a '[[c c c]
         [y y y]
         [m m m]])
(def b '[[r g b]
         [r g b]
         [r g b]])

(map (partial partition 2) (map interleave a b))
;=> (((c r) (c g) (c b)) 
;    ((y r) (y g) (y b))
;    ((m r) (m g) (m b)))

If for some reason you need to convert the answer to nested vectors, it might be worth a look at this question.

2
votes

Here's another implementation:

(defn combine-vectors [& vecs]
  (apply map (partial map vector) vecs))

Replace map with mapv to get vectors instead of lazy seqs out of this.