Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clojure for sequence comprehnsion adding two elements at a time

Tags:

clojure

The comprehension:

(for [i (range 5])] i)

... yields: (0 1 2 3 4)

Is there an idiomatic way to get (0 0 1 1 2 4 3 9 4 16) (i.e. the numbers and their squares) using mostly the for comprehension?

The only way I've found so far is doing a:

(apply concat (for [i (range 5)] (list i (* i i))))
like image 750
Marcus Junius Brutus Avatar asked Apr 26 '26 21:04

Marcus Junius Brutus


2 Answers

Actually, using only for is pretty simple if you consider applying each function (identity and square) for each value.

(for [i (range 5),             ; for every value
      f [identity #(* % %)]]   ; for every function
  (f i))                       ; apply the function to the value

 ; => (0 0 1 1 2 4 3 9 4 16)
like image 141
Beyamor Avatar answered Apr 30 '26 07:04

Beyamor


Since for loops x times, it will return a collection of x values. Multiple nested loops (unless limited by while or when) will give x * y * z * ... results. That is why external concatenation will always be necessary.

A similar correlation between input and output exists with map. However, if multiple collections are given in map, the number of values in the returned collection is the size of the smallest collection parameter.

=> (map (juxt identity #(* % %)) (range 5))
([0 0] [1 1] [2 4] [3 9] [4 16])

Concatenating the results of map is so common mapcat was created. Because of that, one might argue mapcat is a more idiomatic way over for loops.

=> (mapcat (juxt identity #(* % %)) (range 5))
(0 0 1 1 2 4 3 9 4 16)

Although this is just shorthand for apply concat (map, and a forcat function or macro could be created just as easily.

However, if an accumulation over a collection is needed, reduce is usually considered the most idiomatic.

=> (reduce (fn [acc i] (conj acc i (* i i))) [] (range 5))
[0 0 1 1 2 4 3 9 4 16]

Both the for and map options would mean traversing a collection twice, once for the range, and once for concatenating the resulting collection. The reduce option only traverses the range.

Care to share why "using mostly the for comprehension" is a requirement ?

like image 42
NielsK Avatar answered Apr 30 '26 08:04

NielsK