Mapping a function on the values of a map in Clojure

前端 未结 11 1498
面向向阳花
面向向阳花 2020-11-29 16:03

I want to transform one map of values to another map with the same keys but with a function applied to the values. I would think there was a function for doing this in the c

11条回答
  •  半阙折子戏
    2020-11-29 16:20

    map-map, map-map-keys, and map-map-values

    I know of no existing function in Clojure for this, but here’s an implementation of that function as map-map-values that you are free to copy. It comes with two closely related functions, map-map and map-map-keys, which are also missing from the standard library:

    (defn map-map
        "Returns a new map with each key-value pair in `m` transformed by `f`. `f` takes the arguments `[key value]` and should return a value castable to a map entry, such as `{transformed-key transformed-value}`."
        [f m]
        (into (empty m) (map #(apply f %) m)) )
    
    (defn map-map-keys [f m]
        (map-map (fn [key value] {(f key) value}) m) )
    
    (defn map-map-values [f m]
        (map-map (fn [key value] {key (f value)}) m) )
    

    Usage

    You can call map-map-values like this:

    (map-map-values str {:a 1 :b 2})
    ;;           => {:a "1", :b "2"}
    

    And the other two functions like this:

    (map-map-keys str {:a 1 :b 2})
    ;;         => {":a" 1, ":b" 2}
    (map-map (fn [k v] {v k}) {:a 1 :b 2})
    ;;    => {1 :a, 2 :b}
    

    Alternative implementations

    If you only want map-map-keys or map-map-values, without the more general map-map function, you can use these implementations, which don’t rely on map-map:

    (defn map-map-keys [f m]
        (into (empty m)
            (for [[key value] m]
                {(f key) value} )))
    
    (defn map-map-values [f m]
        (into (empty m)
            (for [[key value] m]
                {key (f value)} )))
    

    Also, here’s an alternative implementation of map-map that is based on clojure.walk/walk instead of into, if you prefer this phrasing:

    (defn map-map [f m]
        (clojure.walk/walk #(apply f %) identity m) )
    

    Parellel versions – pmap-map, etc.

    There are also parallel versions of these functions if you need them. They simply use pmap instead of map.

    (defn pmap-map [f m]
        (into (empty m) (pmap #(apply f %) m)) )
    (defn pmap-map-keys [f m]
        (pmap-map (fn [key value] {(f key) value}) m) )
    (defn pmap-map-values [f m]
        (pmap-map (fn [key value] {key (f value)}) m) )
    

提交回复
热议问题