Dictionary 如何在Clojure中用y更新映射值x?

Dictionary 如何在Clojure中用y更新映射值x?,dictionary,clojure,clojurescript,Dictionary,Clojure,Clojurescript,我试图在Clojure中创建一个函数,该函数将map、x和y值作为参数,然后遍历map中的所有元素,并可能用y替换所有x值(如果有的话) 例如,如果我有一个类似于{:a1:b2:c1}的映射,并且我将使用参数[map 1“it works!”]调用该函数,则该函数应返回以下映射:{:a“it works!”:b2:c“it works!” 因此,它会将所有键替换为值1,将键替换为值“it works!”!“ 事先已经感谢您的帮助!一种方法是使用for遍历映射的键和值,并使用进入构建新映射: (d

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

例如,如果我有一个类似于
{:a1:b2:c1}
的映射,并且我将使用参数[map 1“it works!”]调用该函数,则该函数应返回以下映射:
{:a“it works!”:b2:c“it works!”

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


事先已经感谢您的帮助!

一种方法是使用
for
遍历映射的键和值,并使用
进入
构建新映射:

(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}

一种方法是使用
for
遍历映射的键和值,并使用
进入
构建新映射:

(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}

您可以在任何具有函数的窗体上执行此操作:

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

注意:此版本使用了
prewalk
,原因是。

您可以在具有以下函数的任何形式上执行此操作:

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

注:本版本使用了
prewalk
,原因是。

可还原友好型版本将直接使用
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{:x1:y2:z1}1“它有效!”) =>{:x“它有效!”,:y2,:z“它有效!”}


(如果您不能将此代码置于默认的CC-BY SA下,我特此将其置于Apache 2.0许可证下)

一个可简化的友好版本将直接使用
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{:x1:y2:z1}1“它有效!”) =>{:x“它有效!”,:y2,:z“它有效!”}

(我在此将此代码置于Apache 2.0许可证下,如果您无法将其置于默认的CC-BY SA下)

从开始,我们可以修改初始映射,而不是构建新映射:

(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)))
这些变化应该会使事情加快一点

(我在此将此代码置于Apache 2.0许可证下,如果您无法将其置于默认的CC-BY SA下)

从开始,我们可以修改初始映射,而不是构建新映射:

(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)))
这些变化应该会使事情加快一点


(如果您不能将此代码置于默认的CC-BY SA下,我特此将其置于Apache 2.0许可证下)

函数
映射VAL
已经存在。它将函数
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
还有一个姐妹函数
映射键

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

函数
map vals
已经存在。它将函数
tx fn
应用于map中的每个值,创建一个新的输出map。单元测试显示该函数起作用:

  (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
还有一个姐妹函数
映射键

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

要启动的Specter解决方案:

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

要启动的Specter解决方案:

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


这需要对地图进行线性搜索,这并不理想。尽管如此,这可以通过使用
map
for
来实现。您是否尝试过使用这两种方法中的任何一种?看看
fmap
函数,它是这样做的:这将需要对地图进行线性搜索,这并不理想。尽管如此,这可能是可行的可以简单地使用
map
for
来完成。您尝试过使用这两种方法中的任何一种吗?看看
fmap
函数,它会这样做:抱歉!修复了。在if的else子句中用
x
代替了
v
。抱歉!修复了。在if的else子句中用
x
代替了
v
if.That是真的。但是,我不知道任何不在映射上迭代的解决方案。这是真的。但是,我不知道任何不在映射上迭代的解决方案。对我来说很好。你能把它放在ASL下吗?否则OP不能在非CC代码中使用你的扩展。@StefanKamphausen Done。对我来说很好。你能把它放在u下吗nder ASL?否则OP不能在非CC代码中使用您的扩展。@Stefankaphausen Done.interest.Postwalk只查看值,而不是键?@johnbakers我的原始示例查看表单中的每个值,因此将包括键。添加了另一个使用
prewalk
的示例,该示例仅尝试替换映射值。但是(fn[e](if(=e v)r(e))如果e是k/v对,那怎么可能仅仅是值v,它排除了键?换句话说,为什么你的地图上的第一个版本的示例会像你的示例所建议的那样工作?它的功能与你的地图上的第二个版本相同,但我不明白这是怎么回事。这两个版本都在替换值,而不仅仅是第二个版本。@johnbakers try在窗体上使用
prewalk demo
postwark demo
查看它是如何遍历的。是的,该函数将在一个步骤中接收整个映射条目,但它在遍历时也将接收单个键和值。有意思。postwark只查看值,而不是键?@johnbakers我的原始示例查看表单,因此将包括键<