идиоматический способ обновления карт, которые соответствуют предикату в векторе - PullRequest
6 голосов
/ 01 января 2011

У меня есть ссылка на вектор [], к которому добавлены карты.Если я хочу изменить значение элемента карты на основе сопоставления предикатов, каков идиоматический способ сделать это?

Например ...

[{: id 1: name"Джо"} {: id 2: name "Fred"}]

И мы хотим обновить любой идентификатор 2 до имени 'Brian'.

Ответы [ 2 ]

6 голосов
/ 01 января 2011

Вот один из способов:

(def people [ { :id 1 :name "Joe" } { :id 2 :name "Fred" } ])

(defn brian-converter [person] 
  (if (= 2 (:id person)) 
      (assoc person :name "Brian") 
      person))

(map brian-converter people)
;;=> ({:id 1, :name "Joe"} {:id 2, :name "Brian"})

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

(defn create-converter [[key-to-match val-to-match] 
                        key-to-replace val-to-replace]
  (fn [person]
    (if (= val-to-match (key-to-match person))
        (assoc person key-to-replace val-to-replace)
        person)))

(map (create-converter [:id 2] :name "Brian") people)
;;=> ({:id 1, :name "Joe"} {:id 2, :name "Brian"})
(map (create-converter [:id 1] :name "Dude") people)
;;=> ({:id 1, :name "Dude"} {:id 2, :name "Fred"})

Выбор представления аргумента (вектор дляпараметры поиска, развернутые аргументы для замен) в create-converter были для меня как бы произвольны;не уверен, есть ли для этого правило.

4 голосов
/ 01 января 2011

Другой способ - найти индекс карты, которую вы хотите обновить, а затем обновить только эту карту [РЕДАКТИРОВАТЬ: при условии, что вы хотите обновить только один элемент в векторе]:

(def people [{:id 1 :name "Joe"} {:id 2 :name "Fred"}])

(defn vecmap-assoc-pred
  [vm pred & kvs]
  (let [i (some (fn [[i m]] (when (pred m) i))
                (map-indexed vector vm))]
    (apply update-in vm [i] assoc kvs)))

(vecmap-assoc-pred people #(= 2 (:id %)) :name "Brian")

Для этого конкретного случая, вероятно, имеет больше смысла использовать карту людей с ключом id:

(def people {1 {:id 1 :name "Joe"} 2 {:id 2 :name "Fred"}})
(assoc-in people [2 :name] "Brian")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...