如何更改地图子图的值?

时间:2014-07-14 08:44:25

标签: clojure

我是Clojure和函数编程的新手,现在我遇到了问题。我得到了这样一个数据结构:

{
 :service1 \a
 :service2 \b
 :service3 \c
 :default \d
 :alert-a {
           :duration "00:00-23:59"
           :if-alert true
           :continuous-times 2
           :time-interval [2 6 9 15 30 60]
           :times -1
           }
 :alert-b {
           :duration "09:00-23:00"
           :if-alert true
           :continuous-times 2
           :time-interval [2 6 9 15 30 60]
           :times -1
           }
 :alert-c {
           :duration "00:00-23:59"
           :if-alert true
           :continuous-times 5
           :time-interval [5]
           :times 1
           }
 :alert-d {
           :duration "00:00-23:59"
           :if-alert true
           :continuous-times 5
           :time-interval [5 15 30 60]
           :times -1
           }
 }

这是从配置文件中读取的内容。我想使用:duration将所有clj-time值更改为DateTime对象。所以我可以得到类似的东西:

{
 :service1 \a
 :service2 \b
 :service3 \c
 :default \d
 :alert-a {
           :duration DateTime Object
           :if-alert true
           :continuous-times 2
           :time-interval [2 6 9 15 30 60]
           :times -1
           }
 :alert-b {
           :duration DateTime Object
           :if-alert true
           :continuous-times 2
           :time-interval [2 6 9 15 30 60]
           :times -1
           }
 :alert-c {
           :duration DateTime Object
           :if-alert true
           :continuous-times 5
           :time-interval [5]
           :times 1
           }
 :alert-d {
           :duration DateTime Object
           :if-alert true
           :continuous-times 5
           :time-interval [5 15 30 60]
           :times -1
           }
 }

但数据结构是不可变的。这是其他语言中的一个简单问题,但现在我不知道在一整个下午之后该怎么做。

那么有人能给我一些建议吗?我使用的数据结构不好吗?或者这个问题可以通过某种方式以某种方式解决。

2 个答案:

答案 0 :(得分:4)

虽然您正在使用不可变数据结构,但您可以轻松高效地返回基于原始数据的新数据结构。

在这种情况下,最简单(如果重复)的解决方案是:

(-> m 
  (update-in [:alert-a :duration] parse-duration)
  (update-in [:alert-b :duration] parse-duration)
  (update-in [:alert-c :duration] parse-duration)
  (update-in [:alert-d :duration] parse-duration))

这里要认识到的重要一点是update-in 不会改变它正在处理的数据结构。相反,它返回一个应用了修改的新数据结构。

线程宏->允许新的数据结构穿过update-in操作,以便最终返回的值是应用了所有更新的原始数据结构。

解析持续时间函数可能看起来像这样:

(defn parse-duration 
   "Convert duration in HH:MM-HH:MM format"
    [s]
    (let [[t1 t2] (clojure.string/split s #"-"))
       (Period. (clj-time.coerce/to-date-time t1) 
                (clj-time.coerce/to-date-time t2))) 

答案 1 :(得分:1)

在函数式编程中,您不需要修改集合,而是创建具有由新值替换的所需值的新集合。幸运的是,Clojure为此提供了许多有用的功能。对于您的情况update-in应该运作良好。它采用集合(例如map),嵌套键序列和应用于键序列定义的最嵌套值的函数。例如:

> (def m {:a 1 :b 2 :c {:c1 1 :c2 2}})
#'sandbox5448/m
> m
{:a 1, :c {:c1 1, :c2 2}, :b 2}
> (update-in m [:c :c1] str)
{:a 1, :c {:c1 "1", :c2 2}, :b 2}

请注意密钥序列1的值[:c :c1]如何转换为"1"

因此,将:duration的{​​{1}}字段转换为:alert-a就像写作一样简单:

DateTime

其中> (update-in your-map [:alert-a :duration] string-to-date) 是转换器功能。