In the book Clojure for the Brave and True at the end of the section covering reduce there's a challenge:
If you want an exercise that will really blow your hair back, try implementing map using reduce
It turns out that this was a lot harder (at least for me, a Clojure beginner) than I thought it would be. After quite a few hours I came up with this:
(defn map-as-reduce
[f coll]
(reduce #(cons (f %2) %1) '() (reverse coll)))
Is a better way to do this? I'm particularly frustrated by the fact that I have to reverse the input collection in order for this to work correctly. It seems somehow inelegant!
Remember that you can efficiently insert at the end of a vector:
(defn map' [f coll]
(reduce #(conj %1 (f %2)) [] coll))
Example:
(map' inc [1 2 3])
;=> [2 3 4]
One difference between this map' and the original map is that the original map returns an ISeq instead of just a Seqable:
(seq? (map inc [1 2 3]))
;=> true
(seq? (map' inc [1 2 3]))
;=> false
You could remedy this by composing the above implementation of map' with seq:
(defn map' [f coll]
(seq (reduce #(conj %1 (f %2)) [] coll)))
The most important difference now is that, while the original map is lazy, this map' is eager, because reduce is eager.
just for fun:
map really accepts more than one collection as an argument. Here is an extended implementation:
(defn map-with-reduce
([f coll] (seq (reduce #(conj %1 (f %2)) [] coll)))
([f coll & colls]
(let [colls (cons coll colls)]
(map-with-reduce (partial apply f)
(partition (count colls)
(apply interleave colls))))))
in repl:
user> (map-with-reduce inc [1 2 3])
(2 3 4)
user> (map-with-reduce + [1 2 3] [4 5] [6 7 8])
(11 14)
The real map calls seq on its collection argument(s) and returns a lazy seq, so maybe this to get it a little closer to the real map?
(defn my-map
[f coll]
(lazy-seq (reduce #(conj %1 (f %2)) [] (seq coll))))
I would have added that as a comment, but I don't have the reputation. :)
You can use conj to append to a vector instead of prepending to a list:
(defn my-map [f coll]
(reduce (fn [result item]
(conj result (f item)))
[] coll))
(my-map inc [1 2 3]) => [2 3 4]
It is more common to reverse the result, not the input. This is a common idiom when handling singly-linked lists in a recursive fashion. It preserves linear complexity with this data structure.
You might want to offer different implementations for other seqs, e. g., vectors, maybe based on conj instead of cons.
I would not worry too much about elegance with this kind of exercise.
As it was already pointed out. You do not have to reverse the input.
cons add an item to the beginning of a sequence (even on vectors) whereas conj will always add in the most natural way, it always add an item in the fastest way possible for the collection. it will add from left to right for list, and from left to right for vectors.
I noticed that most suggested answers use 'reduce' so allow me to suggest this one using mainly recursion:
(defn my-map [f coll]
(loop [f f coll coll acc []]
(if (empty? coll)
acc
(recur f (rest coll) (conj acc (f (first coll)))))))
Related
What's a good way to create a variadic 'for' in Clojure?
I wrote this out:
(defmacro variadic-for
[f colls]
(let [bindings (map (fn [coll] [(gensym) coll]) colls)]
`(for ~(vec (apply concat bindings))
(~f ~#(map first bindings)))))
So I can use this like:
(variadic-for + [[1] [2] [3 4]])
and the result will be every possible sum, where each given collection represents the possible values for that binding.
Is there a better way to do this? I don't know of anything in the Clojure core that is used to create all permutations in this way, other than 'for'.
Maybe cartesian-product from clojure.math.combinatorics?
(defn variadic-for [f colls]
(map #(apply f %)
(apply clojure.math.combinatorics/cartesian-product colls)))
(variadic-for + [[1] [2] [3 4]])
=> (6 7)
I think your macro implementation is great, but implementing it as a function has the advantage of increased composability. For instance, you can pass your variadic-for to a function. Here is an implementation of variadic-for as a function:
(defn combine2 [A B]
(for [a A
b B]
(conj a b)))
(defn combinations [colls]
(reduce combine2 [[]] colls))
(defn variadic-for [f colls]
(map #(apply f %) (combinations colls)))
I believe there is already a combinations function in some library but implementing it yourself, as done above, is easy.
Here is something you cannot do if variadic-for is a macro:
(def combinatorial+ (partial variadic-for +))
(combinatorial+ [[1] [2] [3 4]])
;; => (6 7)
I want to do the following in Clojure as idiomatically as possible:
transduce a collection
associate each element of the input collection with the corresponding element in the output collection
return the result in a hashmap
Is there a succinct way to do this using core library functions?
If not, what improvements can you suggest to the following implementation?
(defn to-hash [coll xform]
(reduce
merge
(map
#(apply hash-map %)
(mapcat hash-map coll (into [] xform coll)))))
something like this should do the trick without intermediate collections:
(defn process [data xform]
(zipmap data (eduction xform data)))
user> (process [1 2 3] (comp (map inc) (map #(* % %))))
;;=> {1 4, 2 9, 3 16}
the docs on eduction say the following:
Returns a reducible/iterable application of the transducers
to the items in coll. Transducers are applied in order as if
combined with comp. Note that these applications will be
performed every time reduce/iterator is called.
so no additional collection is created.
This is any good, of course, as long as there is one-to-one relationship between input and output elements. What is desired output for (process [1 -2 3] (filter pos?)) or (process [1 1 1 2 2 2] (dedupe)) ?
(by the way, your to-hash implementation has the same flaw)
A transducer is a function that takes a reducing function and returns a new reducing function. To make it work with transducers where there is not a one-to-one mapping from elements in the input collection to the output, you will have to use your transducer to create a new reducing function (step2 in the code below) that will associate elements into your hash map. Something like this.
(def ^:dynamic assoc-k nil)
(defn assoc-step [dst x]
(assoc dst assoc-k x))
(defn to-hash [coll xform]
(let [step (xform (completing assoc-step))
step2 (fn [dst x] (binding [assoc-k x] (step dst x)))]
(reduce step2 {} coll)))
This implementation is quite basic and I am not sure to which extent it will work with stateful transducers. But it will work with the stateless ones, such as map and filter.
And we can test it with a transducer that keeps odd elements in the input collection and squares them:
(defn square [x] (* x x))
(to-hash (range 10) (comp (filter odd?) (map square)))
;; => {1 1, 3 9, 5 25, 7 49, 9 81}
How would I create a transducer from the following ordinary code, where combo is the alias for clojure.math.combinatorics:
(defn row->evenly-divided [xs]
(->> (combo/combinations (sort-by - xs) 2)
(some (fn [[big small]]
(assert (>= big small))
(let [res (/ big small)]
(when (int? res)
res))))))
As noted in a comment transducers are only applicable for processing each item. With this is mind I've made the code a little more transducer friendly by shifting the sorting so that it is now being done for each item. I don't think there's anything that can be done about the combinations part however!
(defn row->evenly-divided [xs]
(->> (combo/combinations xs 2)
(some (fn [xy]
(let [res (apply / (sort-by - xy))]
(when (int? res)
res))))))
This is the same function but with an introduced transducer:
(def x-row->evenly-divided (comp
(map (partial sort-by -))
(map (partial apply /))
(filter int?)))
(defn row->evenly-divided-2 [xs]
(->> (combo/combinations xs 2)
(sequence x-row->evenly-divided)
first))
I am constructing a list of hash maps which is then passed to another function. When I try to print each hash maps from the list using map it is not working. I am able to print the full list or get the first element etc.
(defn m [a]
(println a)
(map #(println %) a))
The following works from the repl only.
(m (map #(hash-map :a %) [1 2 3]))
But from the program that I load using load-file it is not working. I am seeing the a but not its individual elements. What's wrong?
In Clojure tranform functions return a lazy sequence. So, (map #(println %) a) return a lazy sequence. When consumed, the map action is applied and only then the print-side effect is visible.
If the purpose of the function is to have a side effect, like printing, you need to eagerly evaluate the transformation. The functions dorun and doall
(def a [1 2 3])
(dorun (map #(println %) a))
; returns nil
(doall (map #(println %) a))
; returns the collection
If you actually don't want to map, but only have a side effect, you can use doseq. It is intended to 'iterate' to do side effects:
(def a [1 2 3])
(doseq [i a]
(println i))
If your goal is simply to call an existing function on every item in a collection in order, ignoring the returned values, then you should use run!:
(run! println [1 2 3])
;; 1
;; 2
;; 3
;;=> nil
In some more complicated cases it may be preferable to use doseq as #Gamlor suggests, but in this case, doseq only adds boilerplate.
I recommend to use tail recursion:
(defn printList [a]
(let [head (first a)
tail (rest a)]
(when (not (nil? head))
(println head)
(printList tail))))
I am learning Clojure and trying to solve Project's Euler (http://projecteuler.net/) problems using this language.
Second problem asks to find the sum of the even-valued terms in Fibonacci sequence whose values do not exceed four million.
I've tried several approaches and would find next one most accurate if I could find where it's broken. Now it returns 0. I am pretty sure there is a problem with take-while condition but can't figure it out.
(reduce +
(take-while (and even? (partial < 4000000))
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
To compose multiple predicates in this way, you can use every-pred:
(every-pred even? (partial > 4000000))
The return value of this expression is a function that takes an argument and returns true if it is both even and greater than 4000000, false otherwise.
user> ((partial < 4000000) 1)
false
Partial puts the static arguments first and the free ones at the end, so it's building the opposite of what you want. It is essentially producing #(< 4000000 %) instead of #(< % 4000000) as you intended, So just change the > to <:
user> (reduce +
(take-while (and even? (partial > 4000000))
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
9227464
or perhaps it would be more clear to use the anonymous function form directly:
user> (reduce +
(take-while (and even? #(< % 4000000))
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
9227464
Now that we have covered a bit about partial, let's break down a working solution. I'll use the thread-last macro ->> to show each step separately.
user> (->> (iterate (fn [[a b]] [b (+ a b)]) [0 1]) ;; start with the fibs
(map first) ;; keep only the answer
(take-while #(< % 4000000)) ;; stop when they get too big
(filter even?) ;; take only the even? ones
(reduce +)) ;; sum it all together.
4613732
From this we can see that we don't actually want to compose the predicates evan? and less-than-4000000 on a take-while because this would stop as soon as either condition was true leaving only the number zero. Rather we want to use one of the predicates as a limit and the other as a filter.