문제

값의 하나의 맵을 동일한 키를 가진 다른 맵으로 변환하지만 값에 적용되는 함수가있는 다른 맵으로 변환하고 싶습니다. Clojure API 에서이 작업을 수행하는 기능이 있다고 생각하지만 찾을 수 없었습니다.

다음은 내가 찾고있는 것을 구현하는 예입니다.

(defn map-function-on-map-vals [m f]
  (reduce (fn [altered-map [k v]] (assoc altered-map k (f v))) {} m))
(println (map-function-on-map-vals {:a "test" :b "testing"} #(.toUpperCase %)))
{:b TESTING, :a TEST}

누구든지 아는 사람이 있습니까? map-function-on-map-vals 이미 존재 함? 나는 그것이 그렇게 생각했을 것입니다 (아마도 더 좋은 이름으로도).

도움이 되었습니까?

해결책

나는 당신을 좋아합니다 reduce 버전은 괜찮습니다. 나는 그것이 관용적이라고 생각합니다. 어쨌든 목록 이해력을 사용하는 버전은 다음과 같습니다.

(defn foo [m f]
  (into {} (for [[k v] m] [k (f v)])))

다른 팁

당신은 사용할 수 있습니다 clojure.algo.generic.functor/fmap:

user=> (use '[clojure.algo.generic.functor :only (fmap)])
nil
user=> (fmap inc {:a 1 :b 3 :c 5})
{:a 2, :b 4, :c 6}

다음은지도를 변환하는 상당히 일반적인 방법입니다. zipmap 키 목록과 값 목록을 가져 와서 새 Clojure 맵을 생성하는 "올바른 일". 당신은 또한 그것을 넣을 수 있습니다 map 열쇠 주위에 그들을 바꾸거나 둘 다.

(zipmap (keys data) (map #(do-stuff %) (vals data)))

또는 기능으로 마무리하려면 :

(defn map-function-on-map-vals [m f]
    (zipmap (keys m) (map f (vals m))))

Clojure Cookbook에서 가져와 Reduce-KV가 있습니다.

(defn map-kv [m f]
  (reduce-kv #(assoc %1 %2 (f %3)) {} m))

이 작업을 수행하는 관용적 인 방법은 다음과 같습니다.

(defn map-function-on-map-vals [m f]
        (apply merge
               (map (fn [[k v]] {k (f v)})
                    m)))

예시:

user> (map-function-on-map-vals {1 1, 2 2, 3 3} inc))
{3 4, 2 3, 1 2}

map-map, map-map-keys, 그리고 map-map-values

나는 이것에 대한 clojure의 기존 기능이 없다는 것을 알고 있지만 여기에 해당 기능의 구현이 있습니다. map-map-values 당신은 자유롭게 복사 할 수 있습니다. 밀접하게 관련된 두 가지 기능과 함께 제공됩니다. map-map 그리고 map-map-keys, 표준 라이브러리에서도 누락 된 것 :

(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) )

용법

전화해도됩니다 map-map-values 이와 같이:

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

다른 두 가지 기능은 다음과 같이합니다.

(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}

대체 구현

당신이 원한다면 map-map-keys 또는 map-map-values, 더 일반적인 map-map 기능, 의존하지 않는 이러한 구현을 사용할 수 있습니다. 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)} )))

또한 다음은 대체 구현이 있습니다 map-map 그것은 기반입니다 clojure.walk/walk 대신에 into,이 문구를 선호하는 경우 :

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

Parellel 버전 - pmap-map, 등.

필요한 경우 이러한 기능의 병렬 버전도 있습니다. 그들은 단순히 사용합니다 pmap 대신에 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) )

저는 Clojure N00B이므로 훨씬 더 우아한 솔루션이있을 수 있습니다. 여기 내 것 :

(def example {:a 1 :b 2 :c 3 :d 4})
(def func #(* % %))

(prn example)

(defn remap [m f]
  (apply hash-map (mapcat #(list % (f (% m))) (keys m))))

(prn (remap example func))

Anon Func는 각 키와 그 값에서 약간의 2리스트를 만듭니다. MapCat은 맵 키 순서 에서이 기능을 실행하고 전체 작품을 하나의 큰 목록으로 연결합니다. "적용 해시 맵"은 해당 시퀀스에서 새 맵을 만듭니다. (% m)은 조금 이상하게 보일 수 있습니다. 관련 값을 찾기 위해 맵에 열쇠를 적용하는 것은 관용적 인 클로 조이입니다.

가장 적극 권장되는 독서 : the Clojure 치트 시트 .

나는 당신을 좋아합니다 reduce 버전. 약간의 변화로 레코드 구조 유형을 유지할 수도 있습니다.

(defn map-function-on-map-vals [m f]
  (reduce (fn [altered-map [k v]] (assoc altered-map k (f v))) m m))

그만큼 {} 대체되었습니다 m. 이러한 변경으로 레코드는 레코드로 남아 있습니다.

(defrecord Person [firstname lastname])

(def p (map->Person {}))
(class p) '=> Person

(class (map-function-on-map-vals p
  (fn [v] (str v)))) '=> Person

시작하여 {}, 기록은 그 기록을 잃습니다 레코딩, 레코드 기능 (예 : 소형 메모리 표현)을 원한다면 유지하고 싶을 수도 있습니다.

(defn map-vals
  "Map f over every value of m.
   Returns a map with the same keys as m, where each of its values is now the result of applying f to them one by one.
   f is a function of one arg, which will be called which each value of m, and should return the new value.
   Faster then map-vals-transient on small maps (8 elements and under)"
  [f m]
  (reduce-kv (fn [m k v]
               (assoc m k (f v)))
             {} m))

(defn map-vals-transient
  "Map f over every value of m.
   Returns a map with the same keys as m, where each of its values is now the result of applying f to them one by one.
   f is a function of one arg, which will be called which each value of m, and should return the new value.
   Faster then map-vals on big maps (9 elements or more)"
  [f m]
  (persistent! (reduce-kv (fn [m k v]
                            (assoc! m k (f v)))
                          (transient {}) m)))
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top