Clojure:如何将一个函数应用于散列图中的一部分条目? [英] Clojure: How do I apply a function to a subset of the entries in a hash-map?

查看:96
本文介绍了Clojure:如何将一个函数应用于散列图中的一部分条目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我想创建一个新的哈希映射,哈希映射将一个函数应用于元素。这是最好的方法是什么?

 (let 
[my-map {:helloWorld尝试this:foobar}]
(println(doToMap my-map [:hello:foo](fn [k](.toUpperCase k)))

这应该会产生一个像

  {:helloWORLD:tryThis:fooBAR} 


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

p>

细分:



它有助于查看它的内外在Clojure中, map的行为类似函数;如果你调用他们像一个键作为参数的函数,则返回与该键相关联的值。因此给定一个键,该键的当前值可以通过以下方式获得:

 (some-map some-key)


b $ b

我们想要获取旧的值,并通过调用 f 函数将它们更改为新值。所以给定单个键,新值将是:

 (f(some-map some-key))

我们要将这个新值与我们的哈希映射中的这个键相关联,替换旧的值。这是 assoc 所做的:

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

引用,因为我们不改变一个哈希映射对象;每当我们调用 assoc 时,我们返回新的,不可变的,改变的哈希映射对象。并且在Clojure中有效,因为当你 assoc 时,哈希映射是持久的和共享结构。)



在我们的地图上重复 assoc 新值,一次一个键。所以我们需要某种循环结构。我们想要的是从我们的原始哈希映射和单个键开始,然后更新该键的值。然后我们获取新的哈希映射和下一个键,并更新下一个键的值。我们对每个键重复一次,一次一个,最后返回我们已经累积的散列图。这是减少的作用。




  • reduce 是一个函数,它接受两个参数:累加器值,这是我们反复保持更新的值;和单个参数在一次迭代中用于做一些积累。

  • reduce 的第二个参数是作为第一个参数传递给此 fn

  • reduce 的第三个参数是要作为第二个参数传递给此<$



因此:

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

我们的映射只是上面的 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 -far some-key))))
amap
keyseq)

Clojure有一个写匿名函数的简写:#(...)是一个匿名的 fn 形式,其中%1 绑定到匿名函数的第一个参数,%2 到第二个等。所以我们从上面的 fn 可以等价写为:

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

/ p>

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


I am not to Clojure and attempting to figure out how to do this.

I want to create a new hash-map that for a subset of the keys in the hash-map applies a function to the elements. What is the best way to do this?

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

This should then result a map with something like

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

解决方案

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

Breakdown:

It helps to look at it inside-out. In Clojure, hash-maps act like functions; if you call them like a function with a key as an argument, the value associated with that key is returned. So given a single key, the current value for that key can be obtained via:

(some-map some-key)

We want to take old values, and change them to new values by calling some function f on them. So given a single key, the new value will be:

(f (some-map some-key))

We want to associate this new value with this key in our hash-map, "replacing" the old value. This is what assoc does:

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

("Replace" is in scare-quotes because we're not mutating a single hash-map object; we're returning new, immutable, altered hash-map objects each time we call assoc. This is still fast and efficient in Clojure because hash-maps are persistent and share structure when you assoc them.)

We need to repeatedly assoc new values onto our map, one key at a time. So we need some kind of looping construct. What we want is to start with our original hash-map and a single key, and then "update" the value for that key. Then we take that new hash-map and the next key, and "update" the value for that next key. And we repeat this for every key, one at a time, and finally return the hash-map we've "accumulated". This is what reduce does.

  • The first argument to reduce is a function that takes two arguments: an "accumulator" value, which is the value we keep "updating" over and over; and a single argument used in one iteration to do some of the accumulating.
  • The second argument to reduce is the initial value passed as the first argument to this fn.
  • The third argument to reduce is a collection of arguments to be passed as the second argument to this fn, one at a time.

So:

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

fn-to-update-values-in-our-map is just the assoc statement from above, wrapped in an anonymous function:

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

So plugging it into reduce:

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

In Clojure, there's a shorthand for writing anonymous functions: #(...) is an anonymous fn consisting of a single form, in which %1 is bound to the first argument to the anonymous function, %2 to the second, etc. So our fn from above can be written equivalently as:

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

This gives us:

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

这篇关于Clojure:如何将一个函数应用于散列图中的一部分条目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆