Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clojure how to execute a function on elements of two seqs concurently?

Tags:

clojure

In Clojure, what is the best way for iterating concurrently on two seqs and calling a function on the two running elements? For example:

(def a (range 3))
(def b (range 100 103))
(defn my-func [] ...) ;some custom code

The code should execute my-func 3 times, like this:

(my-func 0 100)
(my-func 1 101)
(my-func 2 102)

How can I achieve that without defining any function or macro?

like image 219
viebel Avatar asked Feb 02 '12 23:02

viebel


2 Answers

map is exactly what you need, it takes a function and any number of seqs and calls them just as you wish.

(def a (range 3))
(def b (range 100 103))
user=> a
(0 1 2)
user=> b
(100 101 102)

user=> (defn my-func [a b] (str a ":" b))
#'user/my-func

user=> (my-func 1 2)
"1:2"

user=> (map my-func a b)
("0:100" "1:101" "2:102")

and because map is lazy if you want the function to actually run now:

(doall (map my-func a b))
like image 74
Arthur Ulfeldt Avatar answered Oct 06 '22 20:10

Arthur Ulfeldt


You could also try

(doseq [[x y] (map list my-list1 my-list2)]
  (println x y))

(map list list-2 list-2) creates a list where the first element is a list of the first elements of the input lists, the second element is a list of the second elements, ...

We then iterate over the list, using Clojure's destructuring to extract the elements of the original lists.

In general, you want map if you want to use the return value of the function you are applying. If you are merely executing a function for its side effects, I generally use doseq. This case is complicated by the fact that map works in parallel, while doseq iterates over the Cartesian Product of the lists it is given, so you need both map and doseq to get the behavior we want.

like image 36
Retief Avatar answered Oct 06 '22 21:10

Retief