Map with repeated argument clojure - clojure

Consider the following function as an example:
(defn f [x y] (+ x y))
I want to use this function to add 2 to each element of a vector:
[1 2 6 3 6]
I can use map:
(map f [1 2 6 3 6] [2 2 2 2 2])
But it seems a little ugly creating the second vector where every element is exactly the same.
So I thought using a closure was a better approach:
(map (fn g [x] (f x 2)) [1 2 6 3 6])
So my question is:
In clojure, what is the best way to use map when some arguments are not changing?

Just apply partial function
(map (partial + 2) [1 2 6 3 6]) => (3 4 8 5 8)

Approach 1: use repeat.
(repeat 2) gives you a lazy sequence of infinite 2s
In your case,
(map f [1 2 6 3 6] [2 2 2 2 2])
should be converted into
(map f [1 2 6 3 6] (repeat 2))
Approach 2: use anonymous function
(map #(f % 2) [1 2 6 3 6])

Related

In clojure how to map over overlapping pairs?

Say I have the sequence:
[1 2 3 4 5]
And I want to map over them in the pairs:
[(1, 2), (2, 3), (3, 4), (4, 5)]
I have tried:
(map f (partition 2 [1 2 3 4]))
But this results in the sequence of pairs:
[(1, 2), (3, 4)]
How can I get the desired functionality?
By default partiton returns non-overlapping partitions, but you can supply a step argument to provide the offset at which partitions are created:
clojure.core/partition
([n coll] [n step coll] [n step pad coll])
Returns a lazy sequence of lists of n items each, at offsets step
apart. If step is not supplied, defaults to n, i.e. the partitions
do not overlap. If a pad collection is supplied, use its elements as
necessary to complete last partition upto n items. In case there are
not enough padding elements, return a partition with less than n items.
This will do what you want:
(partition 2 1 [1 2 3 4 5 6 7 8]))
; #=> ((1 2) (2 3) (3 4) (4 5) (5 6) (6 7) (7 8))
An alternative would be map both with the list you have and the rest of the list. E.g.:
(user=> (let [l [1 2 3 4 5]] (map list l (rest l)))
((1 2) (2 3) (3 4) (4 5))
I would do it as follows
; first generate data
; (that is if you really are talking about all the ints)
(map (juxt identity inc) [1 2 3 4 5])
=> ([1 2] [2 3] [3 4] [4 5] [5 6])
; inline example
(map (comp
(fn [[a b]] (println a b)) ; this would be your f
(juxt identity inc)) [1 2 3 4 5])
; using your function f
(map (comp
f
(juxt identity inc)) [1 2 3 4 5])
This also works independent of the order of numbers in your vector:
(let [a [5 4 3 2 1] b (rest a)] (map vector a b))
will yield:
([5 4] [4 3] [3 2] [2 1])

Clojure: 'folding' a sequence (partitioning, as it turned out)

What is the right way of turning a flat list like this:
(1 2 3 4 5 6 7 8 9)
into a sequence of vectors:
([1 2 3] [4 5 6] [7 8 9])
Sorry, I suppose this is something right out of the toolbox, but I can't think of the right keyword.
(->> '(1 2 3 4 5 6 7 8 9) (partition 3) (map vec))
Take the original list and then partition it by 3 and finally map each partition to a vector.
I think using the ->> macro makes it read nicer.
user> (def flat-seq (range 1 10))
#'user/flat-seq
user> (map vec (partition-all 3 flat-seq))
;=> ([1 2 3] [4 5 6] [7 8 9])

clojure implicit map explanation

I understand how map works but I am confused by this example:
(def check-sum
(fn [sequence]
(apply + (map *
(range 1 (inc (count sequence)))
sequence))))
The map part looks like this when given a sequence:
(map * (range 1 (inc (count [5 1 1 4 7 7 1 3 1 0]))) [5 1 1 4 7 7 1 3 1 0])
Which returns this:
(5 2 3 16 35 42 7 24 9 0)
I do not understand where the current item in the map is being multiplied. I would understand if it was using an anonymous function of the form #(* %) etc.
But there is no anonymous function in this example.
The first argument of map should be function and the number of parameter should be matched to the number of collections provided. So, if you want to pass an anonymous function, you should write the code like this:
(map #(* %1 %2) [1 3 5] [2 4 6])
;=> (2 12 30)
(map #(* %1 %2 %3) [1 3 5] [2 4 6] [3 5 7])
;=> (6 60 210)
But * itself is a function which can take any number of arguments (check (doc *) from REPL), you can write the code in a simpler form:
(map * [1 3 5] [2 4 6])
;=> (2 12 30)
(map * [1 3 5] [2 4 6] [3 5 7])
;=> (6 60 210)
* is applied to the set of first elements of each collection, set of second elements, ...
Other functions like +, -, / can be used in this way, too.
No anonymous function is needed, because the named function * is what's doing the multiplying. Two collections are passed to map, so it passes the corresponding elements from each collection to the * function.

Clojure, concat multiple sequences into one

The following line: (repeat 4 [2 3])
gives me this: ([2 3] [2 3] [2 3] [2 3])
How do I create one vector or list from the above list of vectors so that I get this?: [2 3 2 3 2 3 2 3]
Thanks
concat is in fact exactly the function you want
user> (apply concat (repeat 4 [2 3]))
(2 3 2 3 2 3 2 3)
this even works with lazy input:
user> (take 8 (apply concat (repeat [2 3])))
(2 3 2 3 2 3 2 3)
This is an alternative:
user> (def flatten-1 (partial mapcat identity))
#'user/flatten-1
user> (flatten-1 (repeat 4 [2 3]))
(2 3 2 3 2 3 2 3)
it is compatible with laziness and unlike flatten preserves any substructure (only doing one level of flattening)
user> (take 12 (flatten-1 (repeat [2 3 [4]])))
(2 3 [4] 2 3 [4] 2 3 [4] 2 3 [4])
(take 8 (cycle [2 3]))
;; => (2 3 2 3 2 3 2 3)
(flatten x)
Takes any nested combination of sequential things (lists,
vectors, etc.) and returns their contents as a single, flat sequence.
(flatten nil) returns nil.
(flatten (repeat 4 [2 3])) ;(2 3 2 3 2 3 2 3)
Pedantically speaking, you asked for a vector, so:
(->> [2 3] cycle (take 8) vec)
I feel cycle is a little more appropriate than concat (though it uses concat itself) as it indicates "cycle through the elements of this sequence" rather than "concatenate the following sequences together". Just my two cents, matter of opinion.

Why does concat on vectors evaluate to a list?

Calling concat on vectors returns a list. Being a total noob I would expect that the result would also be a vector. Why the conversion to list?
Example:
user=> (concat [1 2] [3 4] [5 6])
(1 2 3 4 5 6)
; Why not: [1 2 3 4 5 6] ?
concat returns a lazy sequence.
user=> (doc concat)
-------------------------
clojure.core/concat
([] [x] [x y] [x y & zs])
Returns a lazy seq representing the concatenation of the elements in the supplied colls.
you can convert it back to a vector with into:
user=> (into [] (concat [1 2] [3 4] [5 6]))
[1 2 3 4 5 6]
into uses transients so it's pretty quick about it.