142

同じキーを使用して、値に関数を適用して、ある値のマップを別のマップに変換したいと思います。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すでに存在するかどうか知っていますか?私はそれができたと思います(おそらくもっと良い名前でも)。

4

11 に答える 11

98

以下を使用できます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}
于 2010-09-21T05:44:05.913 に答える
41

これは、マップを変換するためのかなり一般的な方法です。 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))))
于 2009-11-04T22:18:17.037 に答える
24

Clojure Cookbook から引用すると、reduce-kv があります。

(defn map-kv [m f]
  (reduce-kv #(assoc %1 %2 (f %3)) {} m))
于 2014-10-22T18:46:37.150 に答える
8

これを行うためのかなり慣用的な方法を次に示します。

(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}
于 2009-11-05T05:09:33.903 に答える
6

map-mapmap-map-keys、およびmap-map-values

Clojure にこのための既存の関数がないことは知ってmap-map-valuesいますが、自由にコピーできるように、その関数の実装を次に示します。密接に関連する 2 つの関数 と が付属してmap-mapmap-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"}

他の 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/walkinto

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

パラレル バージョン –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) )
于 2013-11-24T05:49:19.700 に答える
2

私は 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 関数は、各キーとその f'ed 値から小さな 2 つのリストを作成します。Mapcat は、一連のマップのキーに対してこの関数を実行し、作品全体を 1 つの大きなリストに連結します。「ハッシュマップを適用」は、そのシーケンスから新しいマップを作成します。(% m) は少し奇妙に見えるかもしれませんが、マップにキーを適用して関連付けられた値を検索するための慣用的な Clojure です。

最も強く推奨される資料: The Clojure Cheat Sheet

于 2009-11-04T22:12:37.873 に答える
0

なぜスペクターライブラリについてまだ誰も言及していないのか不思議です。この種の変換を簡単にコーディングできるように (そして、さらに重要なことに、記述されたコードを理解しやすくするために) 作成されていますが、それでも非常にパフォーマンスが高くなります。

(require '[com.rpl.specter :as specter])

(defn map-vals [m f]
  (specter/transform
   [specter/ALL specter/LAST]
   f m))

(map-vals {:a "test" :b "testing"}
          #(.toUpperCase %))

このような関数を純粋な Clojure で書くのは簡単ですが、さまざまなデータ構造で構成される高度にネストされたコードに移行すると、コードはさらに複雑になります。そして、ここでスペクターが登場します。

Clojure TV でこのエピソードを視聴することをお勧めします。このエピソードでは、 spectorの背後にある動機と詳細が説明されています。

于 2020-01-10T10:20:19.847 に答える