地图的 Clojure 向量

Clojure Vector of maps

我是 clojure 编程新手,需要一点帮助。 假设我有一个地图矢量,如图所示。

(def testVMap 
  [ {:name "AAA" :rate 100 } 
    {:name "GEICO" :rate 120 }
    {:name "PROGRESSIVE" :rate 118} ] )

我该如何做一些操作,比如找到 AAA 的费率,或者看看我是否有 ALLSTAR 的费率,如果费率不存在,我希望能够添加它,我知道我可以添加使用 into 或 conj。 但我主要担心的是发现我的地图有一个特定的名称,如果名称存在,我需要将费率更新为新值。

这是一种方法:

(some #(if (= "GEICO" (:name %)) %) testVMap)

也就是说:Return testVMap 中第一个 :name 等于 "GEICO" 的东西。 #(... % ...)定义了一个函数,%作为它的函数参数。这部分(:name %)returns每个图的值: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 在这种情况下);否则,#(...) returns 地图不变。

我会留给你去查找 update 的文档,如果它不能从上下文中自我解释的话。

您也可以使用 mapv 而不是 map

毫无疑问,您会希望将所有这些构建到一个或多个函数中。请记住,函数是 Clojure 中的东西——它们是 "data"、第一个 class 对象等。所以在我使用 inc 的地方,你可以有一个函数参数,以及你定义的函数可以接受另一个函数作为它的参数,然后第一个函数将在代码的 update 部分使用它(而不是 inc)。

关于在您想要的地图不存在时添加地图:如果您不处理一长串地图,我会考虑在不同的步骤中执行此操作。有关可用于测试集合是否包含元素的函数名称,请参阅 Andre 的回答。

但是,请注意,测试向量是否包含不存在的内容需要 Clojure 查看整个向量。使用 Clojure 集而不是向量可能更好,或者考虑使用带有(例如):aaa:geico 等作为键的外部映射。在这种情况下,请查看函数 update-in.

与其直接告诉您如何执行此操作,不如让我向您展示如何找到这种功能。

这两个网站的功能结构很好:

现在您要处理的通常是 集合,如果这不能满足您的要求,您可以寻找特定的 vector 操作。不过第一个应该是collection。然后,您将在两个站点中看到 内容测试 部分。

现在您有以下候选人:

distinct? empty? every? not-every? some not-any?

这里的正确人选是some:

(some (comp (partial = "AAA") :name) testVMap)
;; => true

查看项目是否存在

(first
  (filter
    (comp #{"AAA"} :name)
    [{:name "AAA" :rate 100}
     {:name "GEICO" :rate 120}
     {:name "PROGRESSIVE" :rate 118}]))

正在更新您的结构

如果顺序不重要,您可以将结构重组为 name->rate 的映射。例如:

{"AAA" 100 "GEICO" 120}

然后您可以使用update-inassoc更新汇率。

如果订单 很重要,您可以这样做:

(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}))

当然还有其他选择,但我会首先选择这些。