11

次のようなマップがあるとします。

(def m {:a {:foo "bar"}})

ここで、キー :a in m をいくつかの新しい値で更新したいと思います。

(def vs {:baz "qux"})

これが Python の場合、次のようなことができます。

>>> d = {'a': {'foo': 'bar'}}
>>> d['a'].update({'baz': 'qux'})
>>> d
{'a': {'foo': 'bar', 'baz': 'qux'}}

私が見つけた最も単純な Clojure の同等物は、次のような関数を定義することでした。

(defn update-key
  "
  Updates a given key `k` over a map `m` with a map of values `vs`.
  "
  [k m vs]
  (assoc m k (merge (k m) vs)))

次に、次のように呼び出されます。

(update-key :a m vs)
; => {:a {:foo "bar" :baz "qux"}}

私の質問は次のとおりupdate()です。Python dicts が提供するメソッドと同じ機能を実現するための最も慣用的で正しい方法は何ですか?

4

1 に答える 1

14

あなたが探していると思いますassoc-in

(def m {:a {:foo "bar"}})

(assoc-in m [:a :foo] "qux")
; => {:a {:foo "qux"}}

(assoc-in m [:a :baz] "qux")
; => {:a {:foo "bar", :baz "qux"}}

update-inも同様で、一見の価値があるかもしれません。これは実際には Python の例に近いかもしれません:

(def m {:a {:foo "bar"}})
(def vs {:baz "qux"})

(update-in m [:a] merge vs)
; => {:a {:foo "bar", :baz "qux"}}

アップデート:

キーが変数値 (コンパイル時の定数ではない)であっても、ベクトルに変数を入れることで両方update-inを使用できます。assoc-in

(def m {:a {:foo "bar"}})
(def k' :baz)
(def v' "qux")

(assoc-in m [:a k'] v')
; => {:a {:foo "bar", :baz "qux"}}

キーベクターをプログラムで作成することもできます。

(def m {:a {:foo "bar"}})
(def k' :baz)
(def v' "qux")

(let [ks (conj [:a] k')]
  (assoc-in m ks v'))
; => {:a {:foo "bar", :baz "qux"}}
于 2013-03-19T23:04:25.203 に答える