简体   繁体   English

如何在Clojure中对向量的向量进行迭代?

[英]How do I iterate over a vector of vectors in Clojure?

I have a message with 3 attributes: type, currency and amount. 我有一条带有3个属性的消息:类型,货币和金额。

I have a rule with 4 attributes, a destination, a message type, a currency and an amount. 我有一个带有4个属性的规则,一个目标,一个消息类型,一种货币和一个数量。

I want to go through my rules and find a match to the message on the message type and return the destination, or null if there was no match 我想检查规则,找到与消息类型匹配的消息并返回目标,如果没有匹配,则返回null

I'm using a vector for the fixed positions of the fields in the message and rule, I've defined them as follows: 我将矢量用于消息和规则中字段的固定位置,它们的定义如下:

user=> (def msg [100, "USD", 100])
#’user/msg

user=> (def rules [["FAL" 100 "UKP" 100] ["FBC" 101 "USD" 100]])
#’user/rules

Then I define some functions that extract the message type from a rule and a message: 然后定义一些从规则和消息中提取消息类型的函数:

user=>(defn rule-mt [[_ mt]] mt)
#’user/rule-mt

user=>(defn msg-mt [[mt]] mt)
#’user/msg-mt

I've defined a function to match the message types as follows: 我定义了一个函数来匹配消息类型,如下所示:

user=>(defn match-mt [ msg rule ] ( = ( rule-mt rule ) ( msg-mt msg ) ) )
#’user/match-mt

So I can call this directly as follows to check if it matches the first rule: 因此,我可以按以下方式直接调用它来检查它是否与第一个规则匹配:

user=>(match-mt msg (rules 0))
true

And then to see if it matches the second rule: 然后查看它是否与第二条规则匹配:

(match-mt msg (rules 1))
false

How do I iterate over my rules (vector of vectors) calling my match function and then return the destination field of a matching rule (the first field of the rule) ? 如何遍历调用匹配函数的规则(向量的向量),然后返回匹配规则的目标字段(规则的第一个字段)?

Just do it! 去做就对了! Here's a solution that finds all the rules that match a message using a for and then returns the first of them using first . 这是一个解决方案,它使用for查找与消息匹配的所有规则,然后使用first返回它们中的first However because of laziness, only one succesful match needs to be computed. 但是,由于懒惰,仅需要计算一次成功的匹配。

(defn dest-of-rule [rule] (first rule))
(defn get-dest [msg]
   (first
      (for [r rules
            :when (match-mt msg r)]
         (dest-of-rule r))))

Here's an alternative solution that does the same using filter: 这是使用过滤器执行相同操作的替代解决方案:

(defn get-dest [msg]
   (dest-of-rule (first (filter #(match-mt msg %) rules))))

The first + filter idiom is very common and that's why there's a name for it: find-first . first + filter用法很常见,这就是为什么有一个名字的原因: find-first It is available eg in the package seq-utils ( see here ). 它可以在seq-utils包中找到( 请参阅此处 )。

Is there a specific reason why you are using vectors instead of maps as your data types? 为什么使用向量而不是地图作为数据类型有特定原因吗? By using maps, you could get rid of the helper functions and produce more readable code, in my opinion. 我认为,通过使用地图,您可以摆脱助手功能,并生成更具可读性的代码。

Here's how I would do it: 这是我的处理方式:

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

The match-mt function then becomes: match-mt函数将变为:

(defn match-mt [msg rule] (= (:type msg) (:type rule)))

To get the destination of the first matching rule (similar to the answer provided by opqdonut): 要获取第一个匹配规则的目的地(类似于opqdonut提供的答案):

(defn get-dest [msg]
  (:destination (first (filter (partial match-mt msg) rules))))

You could also write a generic function to check equality of a certain field for two (or more) inputs, and define get-dest in terms of that: 您还可以编写一个泛型函数来检查两个(或多个)输入的某个字段是否相等,并根据此定义get-est:

(defn field= [key & inputs]
  (apply = (map key inputs)))
(defn get-dest [msg]
  (:destination (first (filter (partial field= :type msg) rules))))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM