Clojureでマップ値xをyで更新する方法

私は、Clojureで、x、yの値をパラメータとして取り、それからマップ内のすべての要素を調べ、もしあればすべてのxの値をyに置き換える関数を作成しようとしています。

(defn Change-x-to-y-in-map [map x y]; code here)

たとえば、 {:a 1:b 2:c 1} のようなマップがあり、パラメータを指定してこの関数を呼び出すとしたら[map 1 "正常に動作します!]]。次のマップ: {:a "動作します!" :b 2:c "動作します!}

そのため、値1を持つすべてのキーを値 "it works!"のキーに置き換えます。

ご協力ありがとうございます!

0
fmap 関数を見てください、それはこれを行います: algo/generic/functor.clj#L19 "rel =" nofollow noreferrer "> github.com/clojure/algo.generic/blob/…
追加された 著者 Josh,
それは地図の線形検索を必要とするでしょう、そしてそれは理想的ではありません。とは言っても、これは map または for を使用して簡単に実行できます。どちらかを使ってみましたか?
追加された 著者 Carcigenicate,

6 答え

関数 map-vals は既にTupeloライブラリに存在しますマップ内のすべての値に関数 tx-fn を適用して、新しい出力マップを作成します。ユニットテストはそれを実際に示しています:

  (let [map-123 {:a 1 :b 2 :c 3}
        tx-fn   {1 101 2 202 3 303}]
    (is= (t/map-vals map-123 inc)   {:a   2, :b   3, :c   4})
    (is= (t/map-vals map-123 tx-fn) {:a 101, :b 202, :c 303}))

最初のケースでは、関数 inc が入力マップ(IM)の各値に適用されます。

2番目の例では tx-fn として "変換マップ"を使用しています。それぞれの[k v]の組はそれぞれIMで古い値から新しい値への望ましい変換を示します。したがって、 map-123 の値は次のように変更されています。

1 -> 101
2 -> 202 
3 -> 303

姉妹関数 map-keys も利用できます。

(dotest
  (let [map-123 {1 :a 2 :b 3 :c}
        tx-fn   {1 101 2 202 3 303}]
    (is= (t/map-keys map-123 inc)   {  2 :a   3 :b   4 :c})
    (is= (t/map-keys map-123 tx-fn) {101 :a 202 :b 303 :c}))
2
追加された

Stefanの回答から始めて、新しいマップを作成する代わりに初期マップを変更できます。

(defn update-v [m ov nv] 
  (reduce-kv (fn [acc k v] (if (= v ov) (assoc acc k nv) acc))
             m m))

そして、トランジェントを使って次のように修正することができます。

(defn update-v [m ov nv] 
  (persistent!
    (reduce-kv (fn [acc k v] (if (= v ov) (assoc! acc k nv) acc))
             (transient m) m)))

これらの変更は(hmmmmmm)物事を少しスピードアップするはずです。

(あなたがSOデフォルトCC-BY SAの下でそれを取ることができないならば、私はここにApache 2.0ライセンスの下でこのコードを置く)

2
追加された
@StefanKamphausen完了しました。
追加された 著者 Thumbnail,
は、私にはよく見えますよ。あなたもそれをASLの下に置きますか。そうでなければ、OPはCC以外のコードであなたの拡張を使うことができません。
追加された 著者 Stefan Kamphausen,

clojure.walk 機能:

(defn replace-vals [m v r]
  (walk/postwalk
    (fn [e] (if (= e v) r e))
    m))

(replace-vals {:a 1 :b 2 :c 1} 1 "Hey!")
=> {:a "Hey!", :b 2, :c "Hey!"}

(replace-vals [1 2 3 4 1] 1 "Hey!")
=> ["Hey!" 2 3 4 "Hey!"]

これは入れ子になったフォームに対しても機能します。

(replace-vals {:a 1 :b {:c 1 :d "Bye!"}} 1 "Hey!")
=> {:a "Hey!", :b {:c "Hey!", :d "Bye!"}}

map values のみを置き換えたい場合は、これをリファクタリングできます。

(defn replace-map-vals [m v r]
  (walk/prewalk
    (fn [e] (if (and (map-entry? e) (= (val e) v))
              [(key e) r]
              e))
    m))

(replace-map-vals {1 "not replaced" :replaced 1} 1 "Hey!")
=> {1 "not replaced", :replaced "Hey!"})

に関する問題のため、このバージョンでは prewalk を使用していますポストウォークとマップエントリ

2
追加された
面白い。ポストウォークはキーではなく値だけを見ますか?
追加された 著者 johnbakers,
しかし、(fn [e](if(= e v)r e))eがk/vのペアの場合、どうすればキーを除外した値vだけになるのでしょうか。
追加された 著者 johnbakers,
言い換えれば、あなたの例が示唆するように、なぜあなたの地図上のあなたの最初のバージョンの例はうまくいくのでしょうか?それはあなたの2番目のバージョンと同じ機能を持っていますが、私はそれがどのようにできるのかわかりません。 2つ目のバージョンだけでなく、両方のバージョンが値を置き換えています。
追加された 著者 johnbakers,
私の最初の例では、フォーム内のすべての値を調べているので、キーが含まれます。マップ値を置き換えることのみを試みる prewalk を使った別の例を追加しました。
追加された 著者 Taylor Wood,
@johnbakersは、フォーム上で prewalk-demo または postwalk-demo を使用して、その移動方法を確認します。はい、関数 は1ステップでマップエントリ全体を受け取りますが、移動するにつれて個々のキーと値も受け取ります。
追加された 著者 Taylor Wood,

還元可能なバージョンは直接 reduce-kv を使います。

(defn update-v [m ov nv] 
  (reduce-kv (fn [acc k v]
              (assoc acc k (if (= v ov) nv v)))
             {} m))

(update-v {:x 1 :y 2 :z 1} 1 "It Works!") => {:x "It Works!", :y 2, :z "It Works!"}

(あなたがSOデフォルトCC-BY SAの下でそれを取ることができないならば、私はここにApache 2.0ライセンスの下でこのコードを置く)

2
追加された
要件が間違っています。コメントを削除しました。
追加された 著者 Thumbnail,
追加された 著者 Thumbnail,
それは本当です。ただし、地図上で反復しない解決策はわかりません。
追加された 著者 Stefan Kamphausen,

起動するための幽霊の解決策:

(defn replace-vals [m v r] 
    (setval [MAP-VALS (partial = v)] r m))
0
追加された

1つの方法は、 for を使用してマップのキーと値を繰り返し、 into を使用して新しいマップを作成することです。

(defn val-replace [m x y]
  (into {} (for [[k v] m]
             [k (if (= v x) y v)])))

> (val-replace {:x 1 :y 2 :z 1} 1 "It Works!")
{:x "It Works!", :y 2, :z "It Works!"}

> (val-replace1 {:a "" :b 4 :c ""} "" nil)
{:a nil, :b 4, :c nil}
0
追加された
ごめんなさい!一定。 ifのelse節に v の代わりに x を入れてください。
追加された 著者 jas,
どうもありがとうございました!それは今働きます:)
追加された 著者 Ville Lehtonen,