clojure: фильтрация вектора карт по наличию и значению ключей

У меня есть такой вектор карт

  (def map1 
    [{:name "name1"
      :field "xxx"}
     {:name "name2"
      :requires {"element1" 1}}
     {:name "name3"
      :consumes {"element2" 1 "element3" 4}}])

Я пытаюсь определить функции, которые принимают на карте, как {"element1" 1 "element3" 6} (т.е.: с n полями или {}) и установил карты в map1, возвращая только те, которые либо не имеют requires а также consumesили иметь меньшее число, связанное с ними, чем число, связанное с этим ключом в предоставленной карте (если у предоставленной карты нет такого ключа, он не возвращается)

но я не понимаю, как приблизиться к рекурсивному циклу карт и фильтрации

(defn getV [node nodes]

  (defn filterType [type nodes]
    (filter (fn [x] (if (contains? x type)
                    false ; filter for key values here
                    true)) nodes))

  (filterType :requires (filterType :consumes nodes)))

1 ответ

Есть два способа взглянуть на такие проблемы: снаружи внутрь или изнутри наружу. Тщательное присвоение имен может реально помочь при работе с вложенными структурами. Например, вызов вектора карт map1 может добавить к путанице.

Начиная снаружи, вам нужна функция предиката для фильтрации списка. Эта функция будет принимать карту в качестве параметра и будет использоваться функцией фильтра.

(defn comparisons [m]
   ...)

(filter comparisons map1)

Я не уверен, что точно понимаю сравнения, но, кажется, есть как минимум два вкуса. Первый ищет карты, которые не имеют: требуют или: потребляет ключи.

(defn no-requires-or-consumes [m]
   ...)

(defn all-keys-higher-than-values [m]
  ...)

(defn comparisons [m]
   (some #(% m) [no-requires-or-consumes all-keys-higher-than-values]))

Тогда это вопрос определения отдельных функций сравнения

(defn no-requires-or-consumes [m]
   (and (not (:requires m)) (not (:consumes m))))

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

(defn all-keys-higher-than-values [m]
  (every? keys-higher-than-values [(:requires m) (:consumes m)]))

Суть сравнения заключается в том, что число в ключевой части карты зависит от значения. Выдвижение деталей вниз на уровень дает:

(defn keys-higher-than-values [m]
  (every? #(>= (number-from-key %) (get m %)) (keys m)))

Примечание: я выбрал>= здесь, чтобы вторая запись в примере данных прошла.

Это оставляет только потянув номер ключевой строки. как это сделать можно найти в Clojure, как я могу преобразовать строку в число?

(defn number-from-key [s]
    (read-string (re-find #"\d+" s)))

Объединяя все это вместе и работая с данными примера, получаем первую и вторую записи.

Собираем все вместе:

(defn no-requires-or-consumes [m]
   (and (not (:requires m)) (not (:consumes m))))

(defn number-from-key [s]
   (read-string (re-find #"\d+" s)))

(defn all-keys-higher-than-values [m]
  (every? keys-higher-than-values [(:requires m) (:consumes m)]))

(defn keys-higher-than-values [m]
 (every? #(>= (number-from-key %) (get m %)) (keys m)))

(defn comparisons [m]
  (some #(% m) [no-requires-or-consumes all-keys-higher-than-values]))

(filter comparisons map1)
Другие вопросы по тегам