如何在 Clojure 中按值的真实性并行过滤数据?

How to parallel filter data by value's truthy in Clojure?

我们有这样的数据:

(def x {:title ["NAME" "CODE" "ORDER" "MIN" "MAX" "IMG"]
        :show-in-list [true true true true false false]
        :key [:name :code :order :min :max :image]
        :input-type [:txt :txt :num :num :num :img]
        :value [nil nil nil nil nil nil]
        :required [true true false false false false]})

我们想通过 :required 的布尔值过滤这些值,结果是:

{:title ["NAME" "CODE"],
 :show-in-list [true true],
 :key [:part_name :part_code],
 :input-type [:txt :txt],
 :value [nil nil],
 :required [true true]}
(defn bar [state [required value]]
  (if required (conj state value) state))

(defn foo [required values]
  (reduce bar [] (map vector required values)))

(zipmap (keys x) (map #(foo (:required x) %) (vals x)))

We want to filter these values by :required's bool value

将所需值与值配对,如果需要则将值添加到新集合

您可以使用“:required”向量过滤每个元素:

(let [x {:title        ["NAME" "CODE" "ORDER" "MIN" "MAX" "IMG"]
         :show-in-list [true false true true false false]
         :key          [:name :code :order :min :max :image]
         :input-type   [:txt :txt :num :num :num :img]
         :value        [nil nil nil nil nil nil]
         :required     [true true false false false false]}]
  (->> x
       (map (fn [[k v]]
              ;; value v (which is a vector) is filtered out by its :required filter
              [k  (->> (map #(if %1 %2 ::false) (:required x) v)
                       ;; remove ::false element
                       (remove #(= ::false %)))]))
       ;; add the updated key-value pair
       (into (empty x))))

returns...

{:title        ("NAME" "CODE"),
 :show-in-list (true false),
 :key          (:name :code),
 :input-type   (:txt :txt),
 :value        (nil nil),
 :required     (true true)}

我会建议稍微不同的方法: 由于您已经需要过滤掉此 'packed' 数据结构中的数据,我猜您可能需要对其执行一些其他操作,所以将 unpack/decompose 数据结构分开不是更好吗地图?

它可能看起来像这样:

(defn decompose [data]
  (let [ks (keys data)]
    (apply map #(zipmap ks %&) (vals data))))

这个解压数据:

user> (decompose x)


({:title "NAME",
  :show-in-list true,
  :key :name,
  :input-type :txt,
  :value nil,
  :required true}
 {:title "CODE",
  :show-in-list true,
  :key :code,
  :input-type :txt,
  :value nil,
  :required true}
  ;;....more maps
)

然后 recompose:

(defn recompose [data]
  (when (seq data)
    (apply merge-with
           conj
           (zipmap (keys (first data)) (repeat []))
           data)))

这一个,反过来,打包回解包的数据。

所以现在您的任务可以通过简单地过滤分解的数据并将其重新组合来完成:

(->> x
     decompose
     (filter :required)
     recompose)

;;=> {:title ["NAME" "CODE"],
;;    :show-in-list [true true],
;;    :key [:name :code],
;;    :input-type [:txt :txt],
;;    :value [nil nil],
;;    :required [true true]}

对我来说它看起来更通用,而且(更重要的是)更具可读性。