Clojure Вектор карт
Я новичок в программировании clojure и мне нужно немного помочь. Скажем, у меня есть вектор карт, как показано.
(def testVMap
[ {:name "AAA" :rate 100 }
{:name "GEICO" :rate 120 }
{:name "PROGRESSIVE" :rate 118} ] )
Как мне выполнить некоторые операции, такие как определение уровня AAA или узнать, есть ли у меня ставки, скажем, ALLSTAR, если ставки отсутствуют, я бы хотел добавить их, я знаю, что могу добавить их, используя в или кон. Но моя главная проблема в том, чтобы найти мою карту с конкретным именем, и если имя присутствует, мне нужно обновить показатель до нового значения.
3 ответа
Вот один из методов:
(some #(if (= "GEICO" (:name %)) %) testVMap)
Это говорит: верните первое, что в testVMap
чья :name
равно "GEICO"
, #(... % ...)
определяет функцию, с %
как его функциональный параметр. Эта часть (:name %)
возвращает значение :name
значение для каждой карты.
Если может быть несколько карт "GEICO", и вы хотите их всех, используйте filter
вместо some
,
Вот другая версия:
(some #(and (= "GEICO" (:name %)) %) testVMap)
Вы можете использовать update
также.
РЕДАКТИРОВАТЬ: например:
(map #(if (= "GEICO" (:name %))
(update % :rate inc)
%)
testVMap)
Вот inc
это функция, которая добавляет 1 к числу. Вы должны заменить это функцией, которая выполняет преобразование, которое вы хотите, например, #(+ 10 %)
, или же (partial + 10)
, что одно и то же.
Функция определяется #(...)
проверяет, является ли значение :name
"GEICO", а затем, если это так, обновляет тариф с помощью функции, которую вы предоставляете (inc
в этом случае); иначе, #(...)
возвращает карту без изменений.
Я оставлю это вам, чтобы посмотреть документацию update
, если это не говорит само за себя из контекста.
Вы также можете использовать mapv
вместо map
,
Вы, несомненно, захотите встроить все это в одну или несколько функций. Помните, что функции в Clojure- это "данные", объекты первого класса и т. Д. Так, где я использовал inc
вы можете иметь параметр функции, а определенная вами функция может принять другую функцию в качестве аргумента, которую первая функция затем будет использовать в update
часть кода (вместо inc
).
О добавлении карты, если нужной вам не существует: если вы не имеете дело с длинной последовательностью карт, я бы подумал сделать это на другом этапе. См. Ответ Андре о названиях функций, которые полезны для проверки, содержит ли коллекция элемент.
Однако обратите внимание, что проверка того, содержит ли вектор то, чего нет, требует, чтобы Clojure просмотрел весь вектор. Возможно, лучше использовать набор Clojure, а не вектор, или рассмотреть возможность использования внешней карты с (например) :aaa
, :geico
и т. д. как ключи. В этом случае взгляните на функцию update-in
,
Видя, если предмет существует
(first
(filter
(comp #{"AAA"} :name)
[{:name "AAA" :rate 100}
{:name "GEICO" :rate 120}
{:name "PROGRESSIVE" :rate 118}]))
Обновление вашей структуры
Если порядок не важен, вы можете реорганизовать структуру в карту name->rate. Например:
{"AAA" 100 "GEICO" 120}
Тогда вы можете использовать update-in
или же assoc
обновить курс.
Если порядок важен, вы можете сделать что-то вроде этого:
(mapv
(fn [{:keys [name] :as v}]
(if (= name "AAA")
(assoc v :rate 500)
v))
[{:name "AAA" :rate 100}
{:name "GEICO" :rate 120}
{:name "PROGRESSIVE" :rate 118}])
Добавление в вашу структуру
Вы можете добавить к нему с помощью простого conj
, Итак, вы делаете что-то вроде
(if (has-item? struct) ;; has-item would be defined using the first section of this answer
(update-item struct ...) ;; update-item using the second section of this answer
(conj struct {:name "AAA" :rate 100}))
Конечно, есть и другие варианты, но они будут первыми, на которые я пойду.
Вместо того, чтобы сразу сказать вам, как это сделать, позвольте мне показать вам, как вы найдете такую функцию.
Эти два сайта хорошо структурируют функции:
Теперь, в общем, вы имеете дело с коллекцией, и если она не делает то, что вам нужно, вы можете искать конкретные векторные операции. Но первым должен быть сбор. Затем вы увидите раздел " Тесты контента " на обоих сайтах.
Теперь у вас есть следующие кандидаты:
distinct? empty? every? not-every? some not-any?
Правильный кандидат здесь some
:
(some (comp (partial = "AAA") :name) testVMap)
;; => true