【发布时间】:2015-12-20 01:20:45
【问题描述】:
经过多年的 Java(和 PHP/JavaScript)经验,我刚刚开始学习 Clojure。多么大的挑战:-)
如何以惯用方式更新值映射?当我在地图上使用map 函数时,它不会返回地图,而是返回一个序列。
我正在开发一个小型应用程序,其中有一个任务列表。我想做的是更改某些单独任务中的一些值,然后更新原始任务列表。以下是我正在测试的任务:
(defrecord Task [key name duration])
(def tasks
(atom
{
"t1" (->Task "t1" "Task 1" 10)
"t2" (->Task "t2" "Task 2" 20)
"t3" (->Task "t3" "Task 3" 30)
}
))
我使用字符串键将任务放入哈希映射中,因此它可以快速、直接地访问映射中的任何任务。每个任务也都拥有关键,所以当我将单个任务传递给其他函数时,我知道关键是什么。
为了更新持续时间,我使用map 和update-in 迭代并有选择地更新每个任务的持续时间,并返回修改后的任务。
函数如下:
(defn update-task-durations
"Update the duration of each task and return the updated tasks"
[tasks]
; 1) Why do I have to convert the result of the map function,
; from a sequence then back to a map?
(into {}
(map
(fn [task]
(println task) ; debug
(update-in
task
; 2) Why do I have to use vector index '1' here
; to get the value of the map entry?
[1 :duration]
(fn [duration]
(if (< duration 20)
(+ duration 1)
(+ duration 2)
)
)
)
) tasks))
)
我用这个打印之前/之后的值:
(println "ORIGINAL tasks:")
(println @tasks)
(swap! tasks update-task-durations)
(println "\nUPDATED tasks:")
(println @tasks)
1) 我遇到的主要问题是 map 函数返回一个序列,而不是一个映射,所以我不得不再次使用 into {} 将序列转换回映射,这在我看来是不必要的和低效的。
有没有更好的方法来做到这一点?我应该使用map以外的函数吗?
我能否更好地安排我的数据结构,同时仍然有效地直接访问单个任务?
可以使用into {} 将(可能非常大的)序列转换为地图吗?
2) 此外,在我传递给map 函数的函数参数中,每个任务都由map 提供给我,作为[key value] 形式的向量,当我期望一个映射条目时,所以要从映射条目中获取值,我必须将以下键传递给我的 update-in [1 :duration] 这看起来有点难看,有没有更好/更清晰的方法来访问映射条目而不是使用索引 1向量?
【问题讨论】:
标签: dictionary clojure update-in