如何在Clojure中用y更新地图值x?

时间:2018-04-03 12:20:36

标签: dictionary clojure clojurescript

我正在尝试在Clojure中创建一个函数,它将map,x和y值作为参数,然后遍历map中的所有元素,并可能用y替换所有x值(如果有的话)。

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

例如,如果我有一个像{:a 1 :b 2 :c 1}这样的地图,我会用参数[map 1“它调用函数!”]调用该函数,该函数应返回以下映射:{:a "it works!" :b 2 :c "it works!}

因此它会将值为1的所有键替换为值为“it works!”的键。

先谢谢你的帮助!

6 个答案:

答案 0 :(得分:2)

您可以使用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!"}}

如果您只想替换地图,您可以重构:

(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!"})

请注意,由于an issue with postwalk and map entries,此版本使用prewalk

答案 1 :(得分:2)

可简化版本的版本将直接使用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“它有效!”) => {:x“它有效!”,:y 2,:z“它有效!”}

(如果您不能在SO默认的CC-BY SA下使用此代码,请将此代码置于Apache 2.0许可下)

答案 2 :(得分:2)

Stefan's answer开始,我们可以修改初始地图,而不是建立一个新地图:

(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许可下)

答案 3 :(得分:0)

一种方法是使用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}

答案 4 :(得分:0)

要启动的幽灵解决方案:

(defn replace-vals [m v r] 
    (setval [MAP-VALS (partial = v)] r m))

答案 5 :(得分:-2)

函数map-vals已存在in the Tupelo library。它将函数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)中的每个值。

第二个例子使用"转换图"作为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}))