In Clojure How to update a sub-map correctly?

I just started learning Clojure, after many years of Java experience (and PHP / JavaScript). What a problem :-)

How to update the map of values ​​idiomatically? When I use a function mapon a map, it does not return a map, it returns a sequence.

I am working on a small application where I have a list of tasks. What I would like to do is change some values ​​in some individual tasks, and then update the list of original tasks. Here are the tasks I'm testing:

(defrecord Task [key name duration])

(def tasks
  (atom
    {
     "t1" (->Task "t1" "Task 1" 10)
     "t2" (->Task "t2" "Task 2" 20)
     "t3" (->Task "t3" "Task 3" 30)
     }
    ))

I set tasks in hashmap using a string key to have quick, direct access to any task on the map. Each task also contains a key, so I know what that key is when I pass individual tasks to other functions.

, map update-in .

:

(defn update-task-durations
  "Update the duration of each task and return the updated tasks"
  [tasks]
  ; 1) Why do I have to convert the result of the map function,
  ;    from a sequence then back to a map?
  (into {}
    (map
      (fn [task]
        (println task) ; debug
        (update-in
          task
          ; 2) Why do I have to use vector index '1' here
          ;    to get the value of the map entry?
          [1 :duration]
          (fn [duration]
            (if (< duration 20)
              (+ duration 1)
              (+ duration 2)
              )
            )
          )
        ) tasks))
  )

/:

(println "ORIGINAL tasks:")
(println @tasks)

(swap! tasks update-task-durations)

(println "\nUPDATED tasks:")
(println @tasks)

1) , , , map , , , into {}, .

? , map?

, ?

( ) into {}?

2) , , map, , map, [key value], , , update-in [1 :duration]. , / , 1 ?

+4
2

zipmap:

(defn map-vals
  "Returns the map with f applied to each item."
  [f m]
  (zipmap (keys m)
          (map f (vals m))))

(defn update-task-durations
  [tasks]
  (let [update-duration (fn [duration]
                          (if (< duration 20)
                            (+ 1 duration)
                            (+ 2 duration)))]
    (->> tasks
         (map-vals #(update % :duration update-duration)))))

(swap! tasks update-task-durations)

Clojure < 1.7, (update-in % [:duration] ... .

, , :

(->> tasks
     (map (fn [[k task]]
            [k (update task :duration update-duration)]))
     (into {})

?

map . , , map (map :: (a -> b) -> [a] -> [b]), , , map, seq-of-something.

map seq , -, seq -ing -.

. into , .

+2

: map for

(into {}
   (for [[key value] your-map]
         [key (do-stuff value)]))

- reduce-kv

(reduce-kv 
   (fn [new-map key value] 
         (assoc new-map key (do-stuff value))) 
   {}
   your-map))

, reduce

(reduce (fn [m key]
          (update m key do-stuff))
   your-map
   (keys your-map))  
+2

Source: https://habr.com/ru/post/1620933/


All Articles