Skip to content

Instantly share code, notes, and snippets.

@visibletrap
Last active March 6, 2021 03:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save visibletrap/34b29af24eb33acaf69b1f136c0077a3 to your computer and use it in GitHub Desktop.
Save visibletrap/34b29af24eb33acaf69b1f136c0077a3 to your computer and use it in GitHub Desktop.
(ns rules-to-pred)
(def products
[{:id 1
:department "bedding"
:category "pillow"
:color "white"}
{:id 2
:department "cloth"
:category "shirt"
:color "red"}
{:id 3
:department "kids"
:category "bottle"}
{:id 4
:department "cloth"
:category "t-shirt"
:color "white"}
{:id 5
:department "kids"
:category "onesie"
:color "white"}
{:id 6
:department "cloth"
:category "pants"
:color "black"}
{:id 7
:department "kids"
:category "pants"
:color "black"}
{:id 8
:department "cloth"
:category "shirt"
:color "white"}])
(def rules
[{:condition :match
:attr :department
:value ["cloth" "kids"]
:required true}
{:condition :not-match
:attr :category
:value ["t-shirt" "shorts"]
:required true}
{:condition :not-match
:attr :department
:value "kids"
:required true}
{:condition :match
:attr :color
:value "black"}
{:condition :match
:attr :color
:value "white"}])
; For rules without `:required true`, product needs to be satisfied at least one of them.
(defn rules->pred-fn
[rules]
; Implement me
)
(= (mapv :id (filter (rules->pred-fn rules) products))
[6 8])
@phongphan
Copy link

พยายามแล้วได้ประมาณนี้ครับ

(defn- satisfy-fn [{:keys [condition attr value]}]
  (fn [input]
    (let [input-value (attr input)
          result (if (coll? value)
                   (not (nil? (some #{input-value} value)))
                   (= input-value value))]
      (cond
        (= :match condition) result
        (= :not-match condition) (not result)))))

(defn rules->pred-fn
  [rules]
  (let [{all' true any' false} (group-by #(= true (% :required)) rules)
        all-func (->> (map satisfy-fn all')
                      (apply every-pred))
        any-func (->> (map satisfy-fn any')
                      (apply some-fn))]
    (fn [product]
      (when (and (all-func product) (any-func product))
        product))))

@visibletrap
Copy link
Author

@phongphan หน้าตาออกมาคล้ายของผมมากเลยครับ

@phongphan
Copy link

ไม่ได้ handle กรณีที่ all' หรือ any' มัน empty ไว้แฮะ

@visibletrap
Copy link
Author

ไม่เป็นไรหรอกครับ ผมเขียน test case ไว้แค่นี้ แหะๆ

เดี๋ยวรอดูว่ามีคนทำอีกมั้ยอีกซักหน่อยนะครับแล้วเดี๋ยวผมจะโพสของผมบ้าง

@visibletrap
Copy link
Author

อันนี้ของผมครับ มีเช็ค empty ไว้ด้วย เพราะในงานที่ทำมีกรณี empty จริงๆ ครับ

(defn rule->pred-fn
  [{:keys [value condition attr]}]
  (let [value-set (if (coll? value) (set value) #{value})]
    (case condition
      :match (fn [item]
               (contains? value-set (get item attr)))
      :not-match (fn [item]
                   (not (contains? value-set (get item attr)))))))

(defn rules->pred-fn
  [rules]
  (let [{:keys [required not-required]} (group-by (fn [{:keys [required]}] (if required :required :not-required)) rules)
        required-fn (when (seq required) (apply every-pred (mapv rule->pred-fn required)))
        not-required-fn (when (seq not-required) (apply some-fn (map rule->pred-fn not-required)))]
    (apply every-pred (remove nil? [required-fn not-required-fn]))))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment