2013-04-13 44 views
6

Tôi đang bao quanh đầu xung quanh tiểu bang ở Clojure. Tôi đến từ các ngôn ngữ mà nhà nước có thể bị đột biến. Ví dụ, trong Python, tôi có thể tạo một từ điển, đặt một số chuỗi => số nguyên bên trong, và sau đó đi bộ qua từ điển và tăng giá trị.Cách tăng giá trị trong Bản đồ

Làm cách nào để thực hiện điều này trong Clojure thành ngữ?

Trả lời

1

Chỉ produce một bản đồ mới và sử dụng nó:

(def m {:a 3 :b 4}) 

(apply merge 
    (map (fn [[k v]] {k (inc v) }) m)) 

; {:b 5, :a 4} 
+0

Làm thế nào về một giá trị? Vì vậy, nếu tôi muốn {a: 7: b 4}. Điều gì sẽ xảy ra nếu tôi có một bản đồ các số nguyên và muốn tăng giá trị của câu lệnh key1 => subkey1 => integer ++? –

+1

@DavidWilliams (cập nhật trong bản đồ của tôi [: b] inc) ;; => {: a 1,: b 3} –

+0

OK, điều này tạo ra một bản đồ mới, đúng không? Tôi nghĩ rằng điều này làm cho trạng thái giữ khó hơn. Ví dụ, để tạo một trình phân loại bay, tôi cần phải liên tục cập nhật các thứ được cập nhật trong một cấu trúc đa cấp. key1 => subkey1 => số nguyên. Tôi có cần phải làm một dosync và hoán đổi ma thuật không? –

7
(def my-map {:a 1 :b 2}) 
(zipmap (keys my-map) (map inc (vals my-map))) 
;;=> {:b 3, :a 2} 

Để cập nhật chỉ có một giá trị bằng phím:

(update-in my-map [:b] inc) ;;=> {:a 1, :b 3} 

Kể từ Clojure 1,7 nó cũng có thể sử dụng update:

(update my-map :b inc) 
2

Để cập nhật nhiều giá trị, bạn cũng có thể tận dụng lợi thế của việc giảm sử dụng bộ tích lũy đã được lấp đầy và áp dụng một hàm trên đó và mọi thành viên của bộ sưu tập sau.

=> (reduce (fn [a k] (update-in a k inc)) {:a 1 :b 2 :c 3 :d 4} [[:a] [:c]]) 
{:a 2, :c 4, :b 2, :d 4} 

Hãy nhận biết trong những chìa khóa cần phải được kèm theo trong vectơ, nhưng bạn vẫn có thể làm nhiều update-ins trong cấu trúc lồng nhau như bản cập nhật ban đầu trong.

Nếu bạn đã thực hiện nó một chức năng tổng quát, bạn có thể tự động quấn một vector trên một chìa khóa bằng cách kiểm tra nó với coll ?:

(defn multi-update-in 
    [m v f & args] 
     (reduce 
     (fn [acc p] (apply 
         (partial update-in acc (if (coll? p) p (vector p)) f) 
         args)) m v)) 

mà sẽ cho phép single-level/cập nhật quan trọng mà không cần gói các phím trong vectơ

=> (multi-update-in {:a 1 :b 2 :c 3 :d 4} [:a :c] inc) 
{:a 2, :c 4, :b 2, :d 4} 

nhưng vẫn có thể làm được cập nhật lồng nhau

(def people 
    {"keith" {:age 27 :hobby "needlefelting"} 
    "penelope" {:age 39 :hobby "thaiboxing"} 
    "brian" {:age 12 :hobby "rocket science"}}) 

=> (multi-update-in people [["keith" :age] ["brian" :age]] inc) 
    {"keith" {:age 28, :hobby "needlefelting"}, 
    "penelope" {:age 39, :hobby "thaiboxing"}, 
    "brian" {:age 13, :hobby "rocket science"}} 
0

Tôi đã đùa giỡn với ý tưởng tương tự, vì vậy tôi đã đưa ra:

(defn remap 
    "returns a function which takes a map as argument 
    and applies f to each value in the map" 
    [f] 
    #(into {} (map (fn [[k v]] [k (f v)]) %))) 

((remap inc) {:foo 1}) 
;=> {:foo 2} 

hoặc

(def inc-vals (remap inc)) 

(inc-vals {:foo 1}) 
;=> {:foo 2} 
Các vấn đề liên quan