首页 > 解决方案 > 通过键值交换地图查找中的嵌套特定项目,地图中的位置

问题描述

我们有一个带有此示例数据的光标或原子映射:

    #<Cursor: [:customer] {:name Diego Peña, 

    :addresses [{:id 23, :province Madrid, :country 1, :descripcion aaeeeeeeee iii oooo4444, :locality Gali gali, :country_name SPAIN, :direccion Street Cierva, :id 3, :postalcode 30203, :principal true, :customer 17} 

{:id 35, :province Madrid, :country nil, :descripcion yyy lalala3, :locality Lalala, :direccion calle Maria 3 , :postalcode 333, :principal false, :customer 17} 

{:id 6, :province Madrid, :country 2, :descripcion otra direccioncita444, :locality Leleele, :country_name SPAIN, :direccion Direccion calle Ooo, :postalcode 1236, :main false, :customer 17} 

{:id 27, :province Madrid, :country 1, :descripcion grandisima, :locality Alcantarilla, :country_name SPAIN, :direccion C/ 3 Mayo, :postalcode 3001, :main false, :customer 17}

]}>

我需要通过 id 更改搜索地址的值。我已经设法通过 id 的值找到地址:

(defn get-address [pk]
   (->> @db/customer :addresses (filter #(= (int pk) (int (:id %)))) first)
)

我可以用这个更改所有地址::ok #(swap! db/customer assoc-in [:addresses] %)}). 我需要从 API 响应中更改特定地址的数据。

我接近得到它,但使用这种方法我错过了项目的位置或索引:#(swap! db/client assoc-in [:addresses ¿position or index in map?] %)我们有项目地址的 id。

也许这种方法是错误的,更好的方法?

标签: clojureclojurescript

解决方案


assocassoc-inupdateupdate-in函数也适用于向量。在 Clojure 中,向量是关联数据结构,其中键是数字索引 ( O..n),值是 position 处的项目n

所以你可以这样做:

(assoc [:a :b :c] 1 :new-value)
;;      ^  ^  ^
;;      0  1  2
;; => [:a :new-value :c]

根据您的示例,您将需要以下内容:

(defn address-index-by-id
  "Take an `address` map and look it up by `:id` in the `addresses` list.
   Return the numeric index where it was found, nil if not found."
  [address addresses]
  (->> (map-indexed vector addresses) 
       ;; produce a seq `([0 val-at-index-0] … [n val-at-index-n])`
       (filter (fn [[_index {:keys [id]}]] (= id  (:id address)))) ;; filter by id
       (ffirst) ;; get the index of the first match
       ))

(defn set-address
  "Take a `customer` map and an `address` map. Will put the `address` in the
  customer's addresses list. If an address with the same :id key is already
  present in this list, it will be overwritten."
  [customer address]
  (if-let [existing-index (address-index-by-id address (:addresses customer))]
    (assoc-in customer [:addresses existing-index] address)
    (update customer :addresses conj address)))

用法:

(set-address {:name      "Diego Peña"
              :addresses []}
             {:id       1
              :province "Madrid"})
;; => {:name "Diego Peña", :addresses [{:id 1, :province "Madrid"}]}

(-> {:name      "Diego Peña"
     :addresses [{:id       1
                  :province "Madrid"
                  :main     true}
                 {:id       2
                  :province "Barcelona"
                  :main     false}]}
    (set-address {:id       2
                  :province "Barcelona"
                  :main     true})
    (set-address {:id       1
                  :province "Madrid"
                  :main     false}))
;; => {:name "Diego Peña", :addresses [{:id 1, :province "Madrid", :main false} {:id 2, :province "Barcelona", :main true}]}

;; And of course if your `customer` is stored in an Atom:
(swap! customer set-address {:id 1, :province "Madrid", :main true})

推荐阅读