簡體   English   中英

如何返回具有固定鍵和條件值的 clojure map?

[英]How do I return a clojure map with fixed keys and conditional values?

我有一個 function,它返回一個 map。 鍵是 static,但值是有條件的。 像這樣:

(defn map-returning-function [x y]
  {:a (if (some-test-fn x)  "one value" "other value"
   :b (if (some-test-fn x)   15         25
   :c (if (different-test y) :one       :two})

有沒有更優雅的方法來實現這一點,而無需為每個值編寫if測試? 我能想到的唯一其他方法是

(defn another-map-returning-function [x y]
  (if (some-test-fn x)
    {:a "one value",  :b 15, :c (if (different-test y) :one :two)}
    {:a "other value" :b 25, :c (if (different-test y) :one :two)}))

這對我來說似乎並沒有好多少,因為它重復了條件的每個分支的鍵名,並且重復了 function 調用different-test 天堂禁止我需要cond而不是if

人們可以想到的另一種變體是使用merge 一種情況作為默認值,根據 function arguments 進行修改。 這樣,您可以輕松地對測試進行分組,並在必要時添加一些評論。

(defn map-returning-function
  [x y]
  (merge {:a "other value"
          :b 25
          :c :two}
         (when (some-test-fn x)
           {:a "one value"
            :b 15})
         (when (different-test y)
           {:c :one})))

或者反過來,這取決於你認為是默認的。

(defn map-returning-function
  [x y]
  (merge {:a "one value"
          :b 15
          :c :one}
         (when-not (some-test-fn x)
           {:a "other value"
            :b 25})
         (when-not (different-test y)
           {:c :two})))

這個怎么樣:

(let [test-x (some-test x) test-y (some-test y)] 
  (conj 
    (if test-x {:a "one value" :b 15} {:a "other value" :b 25}) 
    (if test-y {:c :one} {:c :two})))

條件在一個地方執行一次,然后在另一個地方使用。 不過要看具體情況和個人喜好。 更像你的例子的東西可能更干凈:

(let [test-x (some-test x) test-y (some-test y)] 
  {:a (if test-x "one value" "other value")
   :b (if test-x 15 25)
   :c (if test-y :one :two)})

看看你在問什么,我會說一種方法是構建一個看起來像這樣的 function:

(pred-map 
  {:a [some-test-fn "one-value" "other-value"] 
   :b [some-test-fn 15 25] 
   :c [different-test :one :two]} 
  x 
  y)

其中 x 是第一個提到的 function 的所有引用的參數,y 是第二個的參數

實現這一目標的方法可能如下:

(defn get-value [p tv fv a]
  (if (p a) tv fv))

(defn get-predicate-set [m]
  (set (map first (vals m))))

(defn get-arg-map [m args]
  (zipmap (get-predicate-set m) args))

(defn get-arg [p m args]
   ((get-arg-map m args) p)) 

(defn get-key-value-pair-creator [m args]
  (fn [[k [p tv fv]]]
    [k
     (get-value 
       p
       tv
       fv 
       (get-arg p m args))]))


(defn pred-map [m & args]
  (into {}
    (map 
      (get-key-value-pair-creator m args)
      m)))

然而,這些函數依賴於 arguments 通過相等映射到函數(在 go 中似乎有引用),因此它不會將兩個相等的匿名函數理解為同一個函數。

如果您不介意重復 arguments,您可以創建一個更簡單的 function,如下所示:

(pred-map
  {:a [(some-test-fn x) "one value" "other-value"]
   :b [(some-test-fn x) 15 25]
   :c [(different-test y) :one :two]})

通過以下簡單的 function:

(defn pred-map [m] (into {} (for [[k [p tv fv]] m] [k (if p tv fv)])))

或無點風格:

(def pred-map (comp (partial into {}) (partial map (fn [[k [p tv fv]]] [k (if p tv fv)]))))

另一種方法:-)

(defmulti map-returning-function 
    (fn [x y] [ (some-test-fn x) (different-test y) ]))

(let [x-values {true  {:a "one value" :b 15}
                false {:a "other value" :b 25}}
      y-values {true {:c :one} false {:c :two}}]

  (defmethod map-returning-function [false false] [x y]
     (merge (x-values false) (y-values false)))

  (defmethod map-returning-function [true true] [x y]
     (merge (x-values true) (y-values true)))
...)

您的第一個代碼示例對我來說似乎最易讀。 可讀性通常比效率更可取,除非您的代碼有性能關鍵部分。 但這是一種只評估一次條件的方法。 我高度懷疑它的性能對你的代碼有很大的影響。 就優雅而言,我仍然更喜歡您的第一個示例,因為直接查看鍵值對是什么更清楚。

(defn another-map-returning-function [x y]
  (let [first-map (if (some test-fn x) {:a "one value" :b 15}
                                       {:a "other value" :b 25})]
    (assoc first-map :c
                        (if (different-test y) :one :two))))

通過無恥地竊取別人的想法。

(defn map-returning-function [x y]
  (let [x-values  {true  {:a "one value" :b 15}
                   false {:a "other value" :b 25}}
        y-values  {true {:c :one} false {:c :two}}
        x-key     (some-test-fn x)
        y-key     (different-test y) ]
    (merge (x-values x-key) (y-values y-key))))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM