我正在编写一些代码,需要在记录的每个值上map
format
。为了省去重复的写作,如果我可以依赖具有固定顺序的记录,那将非常方便。这基本上是现在的样子:
(defrecord Pet [health max-health satiety max-satiety])
(let [{:keys [health max-health satiety max-satiety]} pet
[h mh s ms] (mapv #(format "%.3f" (double %))
[health max-health satiety max-satiety])]
...)
理想情况下,我想用vals
来写:
(let [[h mh s ms] (mapv #(format "%.3f" (double %)) (vals pet))]
...)
但是我找不到关于seq
时记录是否有保证顺序的任何确定来源。根据我的测试,他们似乎需要订购。我尝试创建海量记录(以防小记录依赖排序的集合):
(defrecord Order-Test [a b c d e f g h i j k l m n o p q r s t u v w x y z
aa bb cc dd ee ff gg hh ii jj kk ll mm nn oo pp qq rr ss tt uu vv ww xx yy zz])
(vals (apply ->Order-Test (range 52)))
=> (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51)
他们似乎确实维持秩序。
任何人都可以验证吗?
对于这种确切的情况,我想我可以reduce-kv
结束记录并重新关联val,然后对其进行解构。但是,那将变得非常庞大。我现在也很好奇,因为我什么都找不到。
答案 0 :(得分:4)
与Clojure中的许多内容一样,由于没有规范,因此不能保证。如果它不在记录的文档字符串中,则您要承担后果自负,即使在当前版本的Clojure中确实如此也是如此。
但是我也要说:从哲学上讲,这并不是真正记录 mean 的内容。记录字段应该具有各自的域语义,并且看起来在您的记录中确实如此。像“拿走该记录的N个有意义的字段,并对其全部进行统一处理”这样的操作是正确的事情,当您将其说明时,便会感到惊讶。
您至少可以做一些您想做的事,而冗余度要小一些
(let [[h mh s ms] (for [k [:health :max-health, :satiety :max-satiety]]
(format "%.3f" (get pet k)))]
...)
我个人会说您对域的建模错误:您显然有一个“资源”(健康和饱腹感)概念,该概念既有“当前”值又有“最大值”。那些应该按资源分组,例如
{:health {:current 50 :max 80}
:satiety {:current 3 :max 10}}
这样做之后,我会说宠物的“资源集”实际上只是一个地图字段,而不是它包含的N个资源的N个字段。这样,整个记录字段的排序问题就根本没有出现。