如何有条件地与clojure向量联合

时间:2012-12-15 00:55:35

标签: clojure

是否有一种更清洁的方法可以在clojure中执行以下操作?

(defn this [x] (* 2 x))
(defn that [x] (inc x))
(defn the-other [x] (-> x this that))

(defn make-vector [thing]
  (let [base (vector (this (:a thing))
                     (that (:b thing)))]
    (if-let [optional (:c thing)]
      (conj base (the-other optional))
      base)))

(make-vector {:a 1, :b 2}) ;=> [2 3]
(make-vector {:a 1, :b 2, :c 3}) ;=> [2 3 7]

通过“清洁工”我的意思是更接近这个:

(defn non-working-make-vector [thing]
  (vector (this (:a thing))
          (that (:b thing))
          (if (:c thing) (the-other (:c thing)))))

(non-working-make-vector {:a 1, :b 2} ;=> [2 3 nil]  no nil, please!
(non-working-make-vector {:a 1, :b 2, :c 3} ;=> [2 3 7]

请注意,我可能想在this中的任意一个键上调用一些任意函数(例如thatthe-otherthing)并将结果放入返回的矢量。重要的是,如果地图中不存在密钥,则不应在向量中放置nil

这与this question类似,但输出是矢量而不是地图,因此我无法使用merge

3 个答案:

答案 0 :(得分:2)

(defn this [x] (* 2 x))
(defn that [x] (inc x))
(defn the-other [x] (-> x this that))

(def k-f-map {:a this
              :b that
              :c the-other})

(def m1 {:a 1 :b 2})
(def m2 {:a 1 :b 2 :c 3})

(defn make-vector [k-f-map m]
  (reduce (fn [res [fk fv]]
            (if (fk m)
              (conj res (fv (fk m)))
              res))
          [] k-f-map))

(make-vector k-f-map m1)
-> [2 3]

(make-vector k-f-map m2)
-> [2 3 7]

答案 1 :(得分:1)

;;; replace [:a :b :c] with a vector of arbitrary functions
;;; of your choice, or perhaps accept a seqable of functions
;;; as an extra argument
(defn make-vector [thing]
  (into [] (keep #(% thing) [:a :b :c])))

;;; from the REPL:
(make-vector {:a 1 :b 2})
; => [1 2]
(make-vector {:a 1 :b 2 :c 3})
; => [1 2 3]

请注意keep仅抛出nil; false将包含在输出中。

答案 2 :(得分:0)

还是使用cond->

您在 make-vector 版本中的 cond-> 函数:

(defn make-vector [thing]
  (cond-> [(this (:a thing))
           (that (:b thing))]
    (:c thing) (conj (the-other (:c thing)))))

您可以有更多条件或将 :a 和 :b 也更改为可选。