【问题标题】:How do I iterate over a vector of vectors in Clojure?如何在 Clojure 中迭代向量的向量?
【发布时间】:2011-12-01 11:17:49
【问题描述】:

我有一条包含 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

如何迭代我的规则(向量的向量)调用匹配函数,然后返回匹配规则的目标字段(规则的第一个字段)?

【问题讨论】:

    标签: vector clojure iteration


    【解决方案1】:

    去做吧!这是一个解决方案,它使用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) 中。

    【讨论】:

      【解决方案2】:

      您使用向量而不是地图作为数据类型是否有特定的原因?在我看来,通过使用地图,您可以摆脱辅助函数并生成更易读的代码。

      我会这样做:

      (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))))
      

      【讨论】:

      • 记录会更好,您可以为钥匙增加一些安全性
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-03
      • 1970-01-01
      • 2016-05-11
      • 1970-01-01
      • 1970-01-01
      • 2017-08-29
      • 1970-01-01
      相关资源
      最近更新 更多