在 Clojure 的嵌套映射中关联多个键/值的惯用方法是什么?

发布于 2024-10-08 13:11:46 字数 309 浏览 7 评论 0原文

想象一下您有一个这样的地图:

(def person {
  :name {
    :first-name "John"
    :middle-name "Michael"
    :last-name "Smith" }})

在一个表达式中更改与 :first-name 和 :last-name 关联的值的惯用方法是什么?

(澄清:假设您想将 :first-name 设置为“Bob”,将 :last-name 设置为“Doe”。我们还假设此映射中还有一些我们想要保留的其他值,因此从头开始构建它不是一个选项)

Imagine you have a map like this:

(def person {
  :name {
    :first-name "John"
    :middle-name "Michael"
    :last-name "Smith" }})

What is the idiomatic way to change values associated with both :first-name and :last-name in one expression?

(Clarification: Let's say you want to set :first-name to "Bob" and :last-name to "Doe". Let's also say that this map has some other values in it that we want to preserve, so constructing it from scratch is not an option)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

晨与橙与城 2024-10-15 13:11:46

这里有几种方法。

user> (update-in person [:name] assoc :first-name "Bob" :last-name "Doe")
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}

user> (update-in person [:name] merge {:first-name "Bob" :last-name "Doe"})
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}

user> (update-in person [:name] into {:first-name "Bob" :last-name "Doe"})
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}

user> (-> person 
          (assoc-in [:name :first-name] "Bob")
          (assoc-in [:name :last-name]  "Doe"))
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}

编辑

update-in 在地图上执行递归 assoc。在这种情况下,它大致相当于:

user> (assoc person :name 
             (assoc (:name person) 
                    :first-name "Bob" 
                    :last-name "Doe"))

当您深入一系列嵌套映射时,键的重复变得越来越乏味。 update-in 的递归可以让您避免一遍又一遍地重复键(例如:name);递归调用之间的中间结果存储在堆栈中。查看 update-in 的源代码,了解它是如何完成的。

user> (def foo {:bar {:baz {:quux 123}}})
#'user/foo

user> (assoc foo :bar 
             (assoc (:bar foo) :baz 
                    (assoc (:baz (:bar foo)) :quux 
                           (inc (:quux (:baz (:bar foo)))))))
{:bar {:baz {:quux 124}}}

user> (update-in foo [:bar :baz :quux] inc)
{:bar {:baz {:quux 124}}}

assoc 是动态的(update-inassoc-in 以及大多数其他对 Clojure 数据结构进行操作的 Clojure 函数也是如此)。如果 assoc 到地图上,它会返回一个地图。如果您assoc到一个向量上,它会返回一个向量。查看 assoc 的源代码并查看 RT.java< /code> Clojure 源代码中的详细信息。

Here are a couple of ways.

user> (update-in person [:name] assoc :first-name "Bob" :last-name "Doe")
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}

user> (update-in person [:name] merge {:first-name "Bob" :last-name "Doe"})
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}

user> (update-in person [:name] into {:first-name "Bob" :last-name "Doe"})
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}

user> (-> person 
          (assoc-in [:name :first-name] "Bob")
          (assoc-in [:name :last-name]  "Doe"))
{:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}

Edit

update-in does recursive assocs on your map. In this case it's roughly equivalent to:

user> (assoc person :name 
             (assoc (:name person) 
                    :first-name "Bob" 
                    :last-name "Doe"))

The repetition of keys becomes more and more tedious as you go deeper into a series of nested maps. update-in's recursion lets you avoid repeating keys (e.g. :name) over and over; intermediary results are stored on the stack between recursive calls. Take a look at the source for update-in to see how it's done.

user> (def foo {:bar {:baz {:quux 123}}})
#'user/foo

user> (assoc foo :bar 
             (assoc (:bar foo) :baz 
                    (assoc (:baz (:bar foo)) :quux 
                           (inc (:quux (:baz (:bar foo)))))))
{:bar {:baz {:quux 124}}}

user> (update-in foo [:bar :baz :quux] inc)
{:bar {:baz {:quux 124}}}

assoc is dynamic (as are update-in, assoc-in, and most other Clojure functions that operate on Clojure data structures). If assoc onto a map, it returns a map. If you assoc onto a vector, it returns a vector. Look at the source for assoc and take a look in in RT.java in the Clojure source for details.

若有似无的小暗淡 2024-10-15 13:11:46

我不确定我的情况是否完全相同,但我有要应用的更改列表:

(def updates [[[:name :first-name] "Bob"] 
              [[:name :last-name] "Doe"]])

在这种情况下,您可以使用 assoc-in 减少该列表,如下所示:

(reduce #(assoc-in %1 (first %2) (second %2)) person updates)

I'm not sure if my case is quite the same but I had list of changes to apply:

(def updates [[[:name :first-name] "Bob"] 
              [[:name :last-name] "Doe"]])

In that case you can reduce over that list with assoc-in like this:

(reduce #(assoc-in %1 (first %2) (second %2)) person updates)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文