在Clojure中将一些哈希映射值转换为浮点数的惯用方法

时间:2016-07-01 08:19:13

标签: clojure

我有一个简单的to-float函数:

(defn to-float [v] (cond
                     (nil? v) nil
                     (string? v) (Float/parseFloat v)
                     :else (float v)))

记录:

(defrecord Product [Id UseRecommendation ReferenceProductId OnePrice TotalPrice
                    ManualTotalPrice MarketTotalPrice PreviousTotalPrice PurchaseTotalPrice
                    Tax Deposit RuleId RoleId PrimaryProduct Size])

对于某些键(?),我希望在将它们传递给map->Product(构造函数?)之前确保它们是浮点数。对不起,我不熟悉这里的术语。

无论如何,我的第一个解决方案非常详细:

(defn init->Product [args]
  (let [converted-args (assoc args
                         :TotalPrice         (to-float (:TotalPrice args))
                         :ManualTotalPrice   (to-float (:ManualTotalPrice args))
                         :MarketTotalPrice   (to-float (:MarketTotalPrice args))
                         :PreviousTotalPrice (to-float (:PreviousTotalPrice args))
                         :PurchaseTotalPrice (to-float (:PurchaseTotalPrice args))
                         :Tax                (to-float (:Tax args))
                         :Deposit            (to-float (:Deposit args)))]
    (map->Product converted-args)))

第二个更好,但在applymergehash-map等方面有很多“噪音”:

(defn init->Product [args]
  (let [apply-float (fn [keys] (merge args (apply merge (map #(hash-map % (to-float (% args))) keys))))]
    (map->Product (apply-float '(:TotalPrice :ManualTotalPrice :MarketTotalPrice :PreviousTotalPrice :PurchaseTotalPrice :Tax :Deposit)))))

第三个解决方案使用递归,这对于Clojure的新手来说也不容易理解:

(defn init->Product [args-orig]
  (let [apply-float (fn [args keys] (if (empty? keys) args (let [key (first keys)] (recur (assoc args key (to-float (key args))) (rest keys)))))]
    (map->Product (apply-float args-orig '(:TotalPrice :ManualTotalPrice :MarketTotalPrice :PreviousTotalPrice :PurchaseTotalPrice :Tax :Deposit)))))

你能想到更简单的事情吗?我有一种感觉,我在这里缺少一个实用功能,或者我没有看到如何使用reduce或其他功能。

编辑:这更像我在Python中的表现

(defn init->Product [args-orig]
  (let [apply-float (fn [args keys] (merge args (into {} (map (fn [key] [key (to-float (key args))]) keys))))]
    (map->Product (apply-float args-orig '(:TotalPrice :ManualTotalPrice :MarketTotalPrice :PreviousTotalPrice :PurchaseTotalPrice :Tax :Deposit)))))

1 个答案:

答案 0 :(得分:3)

您可以使用(assoc m :x (f (:x m)))代替(update m :x f)。所以,我会按如下方式重写你的init->Product函数:

(defn init->Product [args]
  (let [converted-args (reduce #(update %1 %2 to-float)
                               args
                               [:TotalPrice
                                :ManualTotalPrice
                                :MarketTotalPrice
                                :PreviousTotalPrice
                                :PurchaseTotalPrice
                                :Tax
                                :Deposit])]
    (map->Product converted-args)))