Clojure的:我该如何申请一个功能项的子集的哈希地图吗?(Clojure: How do I a

2019-09-02 00:39发布

我不是Clojure的,并试图找出如何做到这一点。

我想创建一个新的哈希映射在哈希映射中键的一个子集应用一个函数的元素。 做这个的最好方式是什么?

(let 
   [my-map {:hello "World" :try "This" :foo "bar"}]
   (println (doToMap my-map [:hello :foo] (fn [k] (.toUpperCase k)))

那么这将导致与一些像那样的地图

{:hello "WORLD" :try "This" :foo "BAR"}

Answer 1:

(defn do-to-map [amap keyseq f]
  (reduce #(assoc %1 %2 (f (%1 %2))) amap keyseq))

分解:

它有助于看看它由内而外。 Clojure中,哈希映射像功能; 如果你叫他们像一键作为自变量的函数,返回与该键关联的值。 这样给定的单个密钥,可以通过获得该密钥的当前值:

(some-map some-key)

我们希望把旧的价值观念,并通过调用一些功能将其更改为新值f他们。 因此,考虑一个键,新的值将是:

(f (some-map some-key))

我们希望这个新的值与此键在我们的哈希地图,“取代”旧的价值相关联。 这是assoc的作用:

(assoc some-map some-key (f (some-map some-key)))

(“替换”是在吓唬引号,因为我们没有变异单哈希映射对象,我们返回新的,不可改变的,改变了哈希映射对象每次我们打电话时assoc ,这是Clojure中仍然快速和有效的,因为哈希地图是持久的,股权结构,当你assoc他们。)

我们需要反复assoc新的价值到我们的地图,一次一个关键。 因此,我们需要某种循环结构。 我们要的是开始与我们原来的哈希地图和一个键,然后“更新”该键的值。 然后我们采取新的哈希映象和下一个键,“更新”确定下一个键的值。 我们重复这对于每一个关键,一次一个,最后返回哈希地图,我们已经“积累”。 这是reduce呢。

  • 第一个参数reduce是一个函数,有两个参数:一个“蓄电池”的价值,这是我们不断“更新”一遍又一遍的价值; 在一个迭代中使用一个单独的参数做一些积累的。
  • 到第二个参数reduce是作为第一个参数,以这种传递的初始值fn
  • 第三个参数reduce是参数的集合作为第二个参数到这个传递fn的时间,一个。

所以:

(reduce fn-to-update-values-in-our-map 
        initial-value-of-our-map 
        collection-of-keys)

fn-to-update-values-in-our-map只是assoc从上面的说法,包裹在一个匿名函数:

(fn [map-so-far some-key] (assoc map-so-far some-key (f (map-so-far some-key))))

因此,将其插入reduce

(reduce (fn [map-so-far some-key] (assoc map-so-far some-key (f (map-so-far some-key))))
        amap
        keyseq)

Clojure中,有用于写入匿名函数的缩写: #(...)是一个匿名fn由单一形式的,其中%1被绑定到的第一个参数的匿名函数, %2到第二等因此,我们的fn从上面可以等价地写为:

#(assoc %1 %2 (f (%1 %2)))

这给了我们:

(reduce #(assoc %1 %2 (f (%1 %2))) amap keyseq)


Answer 2:

(defn doto-map [m ks f & args]
  (reduce #(apply update-in %1 [%2] f args) m ks))

调用示例

user=> (doto-map {:a 1 :b 2 :c 3} [:a :c] + 2)
{:a 3, :b 2, :c 5}

希望这有助于。



Answer 3:

以下似乎工作:

(defn doto-map [ks f amap]
  (into amap
    (map (fn [[k v]] [k (f v)])
         (filter (fn [[k v]] (ks k)) amap))))

user=> (doto-map #{:hello :foo} (fn [k] (.toUpperCase k)) {:hello "World" :try "This" :foo "bar"})
{:hello "WORLD", :try "This", :foo "BAR"}

有可能是一个更好的方式来做到这一点。 也许有人能拿出一个漂亮的一行代码:)



文章来源: Clojure: How do I apply a function to a subset of the entries in a hash-map?