Reputation: 2022
I have a hash-map. I want to iterate over the values and replace each of them depending on the value's type. If the value is an integer, replace it with true
, and if not, replace it with false
. I want this to return a new hash-map with every value updated to either true or false.
(defn my-function [hash-map]
(loop [hash-map hash-map]
(for [value (vals hash-map)]
(if (= Integer (type value))
(recur (assoc hash-map key true))
(recur (assoc hash-map key false))))))
That won't work because Clojure Can only recur from tail position
, but that's the general idea of what I want to do. Any ideas of an effective way to do this? if-let
and update-in
seemed like potential solutions, but I can't quite grasp them.
Upvotes: 11
Views: 7148
Reputation: 49085
The operation you've outlined -- transforming each value in a map, independently -- is actually already implemented in the Functor module.
What you need to do to use it is implement your function that transforms a single value, then fmap
it over your map:
(fmap your-function your-map)
(Don't be misled by the name fmap -- this operation is not specific to maps. Since it's a generic function, it works on anything that has a Functor instance, which also includes lists, sets, and vectors). This is a structure-preserving operation: none of the keys will be changed, no new ones will be added, none will be removed.
If you'd prefer to avoid using a generic function, just check out the implementation:
(defmethod fmap clojure.lang.IPersistentMap
[f m]
(into (empty m) (for [[k v] m] [k (f v)]))) ;;; <== the important part!!
where f = your-function
and m = your-map
.
This library has been moved (is moving? will be moved?) to clojure.algo.generic.functor
. See this for more information, and this for the source.
Upvotes: 5
Reputation: 17299
(reduce-kv (fn [m k v] (assoc m k (= Integer (type v)))) {} m)
Or even shorter if you prefer:
(reduce-kv #(assoc %1 %2 (= Integer (type %3))) {} m)
And to keep the type of map (hash vs. sorted):
(reduce-kv #(assoc %1 %2 (= Integer (type %3))) (empty m) m)
Caveat: the last one doesn't work with records.
Upvotes: 18
Reputation: 3752
(defn f [m]
(reduce (fn [res [k v]]
(assoc res k (= Integer (type v))))
{} m))
Or if you need recursion version
(defn f
([m] (f {} m))
([res m] (if (empty? m)
res
(let [[k v] (first m)]
(recur (assoc res k (= Integer (type v)))
(rest m))))))
Upvotes: 0
Reputation: 91857
(letfn [(map-vals [m f]
(into {} (for [[k v] m]
[k (f v)])))]
(map-vals m #(= Integer (type %))))
Upvotes: 3