我有一条包含3个属性的消息:类型,货币和金额。
我有一个包含4个属性,目的地,消息类型,货币和金额的规则。
我想查看我的规则并找到与消息类型的消息匹配并返回目标,如果没有匹配则返回null
我正在使用向量作为消息和规则中字段的固定位置,我已将它们定义如下:
user=> (def msg [100, "USD", 100])
#’user/msg
user=> (def rules [["FAL" 100 "UKP" 100] ["FBC" 101 "USD" 100]])
#’user/rules
然后我定义了一些从规则和消息中提取消息类型的函数:
user=>(defn rule-mt [[_ mt]] mt)
#’user/rule-mt
user=>(defn msg-mt [[mt]] mt)
#’user/msg-mt
我已经定义了一个匹配消息类型的函数,如下所示:
user=>(defn match-mt [ msg rule ] ( = ( rule-mt rule ) ( msg-mt msg ) ) )
#’user/match-mt
所以我可以直接调用它来检查它是否与第一条规则匹配:
user=>(match-mt msg (rules 0))
true
然后看看它是否与第二条规则匹配:
(match-mt msg (rules 1))
false
如何迭代我的规则(向量矢量)调用我的匹配函数,然后返回匹配规则的目标字段(规则的第一个字段)?
答案 0 :(得分:3)
做吧!这是一个解决方案,它使用for
查找与消息匹配的所有规则,然后使用first
返回第一个规则。但是由于懒惰,只需要计算一次成功的匹配。
(defn dest-of-rule [rule] (first rule))
(defn get-dest [msg]
(first
(for [r rules
:when (match-mt msg r)]
(dest-of-rule r))))
以下是使用过滤器执行相同操作的替代解决方案:
(defn get-dest [msg]
(dest-of-rule (first (filter #(match-mt msg %) rules))))
first
+ filter
成语非常常见,这就是为什么有一个名称:find-first
。它是可用的,例如在包seq-utils(see here)。
答案 1 :(得分:3)
您是否有使用向量而不是地图作为数据类型的具体原因?通过使用map,我可以摆脱辅助函数并生成更易读的代码。
我将如何做到这一点:
(def msg {:type 100 :currency "USD" :amount 100})
(def rules [{:destination "FAL" :type 100 :currency "UKP" :amount 100}
{:destination "FBC" :type 101 :currency "USD" :amount 100}])
match-mt
函数变为:
(defn match-mt [msg rule] (= (:type msg) (:type rule)))
获取第一个匹配规则的目的地(类似于opqdonut提供的答案):
(defn get-dest [msg]
(:destination (first (filter (partial match-mt msg) rules))))
您还可以编写一个泛型函数来检查两个(或更多)输入的某个字段的相等性,并根据它定义get-dest:
(defn field= [key & inputs]
(apply = (map key inputs)))
(defn get-dest [msg]
(:destination (first (filter (partial field= :type msg) rules))))