Clojure의 맵 값에 함수 맵핑
동일한 키를 사용하지만 값에 함수가 적용된 하나의 값 맵을 다른 맵으로 변환하고 싶습니다. 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 요리 책에서 가져온 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}
대체 구현
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) )
I'm a Clojure n00b, so there may well be much more elegant solutions. Here's mine:
(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))
The anon func makes a little 2-list from each key and its f'ed value. Mapcat runs this function over the sequence of the map's keys and concatenates the whole works into one big list. "apply hash-map" creates a new map from that sequence. The (% m) may look a little weird, it's idiomatic Clojure for applying a key to a map to look up the associated value.
Most highly recommended reading: The Clojure Cheat Sheet .
I like your reduce
version. With a very slight variation, it can also retain the type of records structures:
(defn map-function-on-map-vals [m f]
(reduce (fn [altered-map [k v]] (assoc altered-map k (f v))) m m))
The {}
was replaced by m
. With that change, records remain records:
(defrecord Person [firstname lastname])
(def p (map->Person {}))
(class p) '=> Person
(class (map-function-on-map-vals p
(fn [v] (str v)))) '=> Person
By starting with {}
, the record loses its recordiness, which one might want to retain, if you desire the record capabilities (compact memory representation for instance).
(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)))
참고URL : https://stackoverflow.com/questions/1676891/mapping-a-function-on-the-values-of-a-map-in-clojure
'Programing' 카테고리의 다른 글
하스켈에서의 암기? (0) | 2020.07.03 |
---|---|
PHP에서 익명 객체 만들기 (0) | 2020.07.03 |
이메일 뉴스 레터에 Google Plus (하나 또는 공유) 링크 추가 (0) | 2020.07.03 |
Java가 int를 바이트로 변환 할 때 이상한 행동? (0) | 2020.07.03 |
내 JS 파일 캐싱 Chrome 중지 (0) | 2020.07.03 |