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)