Как мне перебрать вектор векторов в Clojure? - PullRequest
2 голосов
/ 01 декабря 2011

У меня есть сообщение с 3 атрибутами: тип, валюта и сумма.

У меня есть правило с 4 атрибутами, пунктом назначения, типом сообщения, валютой и суммой.

Я хочу просмотреть мои правила и найти совпадение с сообщением в типе сообщения и вернуть адресата, или ноль, если совпадения не было

Я использую вектор для фиксированных позиций полей в сообщении и правиле, я определил их следующим образом:

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

Как перебрать правила (вектор векторов), вызывая мою функцию сопоставления, а затем вернуть поле назначения соответствующего правила (первое поле правила)?

Ответы [ 2 ]

3 голосов
/ 01 декабря 2011

Есть ли конкретная причина, по которой вы используете векторы вместо карт в качестве типов данных? Используя карты, вы можете избавиться от вспомогательных функций и создать более читабельный код, на мой взгляд.

Вот как бы я это сделал:

(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))))
3 голосов
/ 01 декабря 2011

Просто сделай это! Вот решение, которое находит все правила, соответствующие сообщению, используя 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 ( см. здесь ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...