Hello, A note about the code organization : I think you should strive to separate the code that does side effects from the code that works on the datastructures.
This means you could refactor your refactored version as such: => (def example (ref [{:id 1 :email {"a...@mail.com" 1}} {:id 2 :email {"d...@mail.com" 1}} {:id 3 :email {"g...@mail.com" 2}} {:id 4 :email {"f...@mail.com" 2}}])) (defn update-counter-val [v id] (let [at-after (drop-while #(not= id (:id %)) v) mod-key (-> at-after first :email keys first) location (- (count v) (count at-after))] (update-in v [location :email mod-key] inc))) (defn update-counter [id xs] (dosync (alter xs update-counter-val id))) (dotimes [_ 3] (update-counter 3 example)) @example #'user/example #'user/update-counter-val #'user/update-counter nil [{:email {"a...@mail.com" 1}, :id 1} {:email {"d...@mail.com" 1}, :id 2} {:email {"g...@mail.com" 5}, :id 3} {:email {"f...@mail.com" 2}, :id 4}] Finally, you could save you some pain if you had a representation of the data that is more amenable to manipulation. Depending on your requirements: - do you really need a vector, or can you go with a set ? e.g. change example to (def example (ref #{{:id 1 :email {"a...@mail.com" 1}} {:id 2 :email {"d...@mail.com" 1}} {:id 3 :email {"g...@mail.com" 2}} {:id 4 :email {"f...@mail.com" 2}}})) This way, you can simplify the manipulation by using clojure.set : => (require '[clojure.set :as s]) (def example (ref #{{:id 1 :email {"a...@mail.com" 1}} {:id 2 :email {"d...@mail.com" 1}} {:id 3 :email {"g...@mail.com" 2}} {:id 4 :email {"f...@mail.com" 2}}})) (defn update-counter-val [v id] (let [r (first (s/select #(= id (:id %)) v)) mod-key (-> r :email keys first)] (-> v (disj r) (conj (update-in r [:email mod-key] inc))))) (defn update-counter [id xs] (dosync (alter xs update-counter-val id))) (dotimes [_ 3] (update-counter 3 example)) @example nil #'user/example #'user/update-counter-val #'user/update-counter nil #{{:email {"a...@mail.com" 1}, :id 1} {:email {"f...@mail.com" 2}, :id 4} {:email {"g...@mail.com" 5}, :id 3} {:email {"d...@mail.com" 1}, :id 2}} Or alternatively, you can have the records indexed in a hashmap: => (require '[clojure.set :as s]) (def example (ref {1 {:id 1 :email {"a...@mail.com" 1}} 2 {:id 2 :email {"d...@mail.com" 1}} 3 {:id 3 :email {"g...@mail.com" 2}} 4 {:id 4 :email {"f...@mail.com" 2}}})) (defn update-counter-val [v id] (let [mod-key (-> id v :email keys first)] (update-in v [id :email mod-key] inc))) (defn update-counter [id xs] (dosync (alter xs update-counter-val id))) (dotimes [_ 3] (update-counter 3 example)) @example nil #'user/example #'user/update-counter-val #'user/update-counter nil {1 {:email {"a...@mail.com" 1}, :id 1}, 2 {:email {"d...@mail.com" 1}, :id 2}, 3 {:email {"g...@mail.com" 5}, :id 3}, 4 {:email {"f...@mail.com" 2}, :id 4}} Also, restructuring the record a little bit could help, but I don't understand what it's about, so I don't know what to suggest. Anyway, you could get rid of computing mod-key by leveraging some more core clojure functions: (require '[clojure.set :as s]) (def example (ref {1 {:id 1 :email {"a...@mail.com" 1}} 2 {:id 2 :email {"d...@mail.com" 1}} 3 {:id 3 :email {"g...@mail.com" 2}} 4 {:id 4 :email {"f...@mail.com" 2}}})) (defn update-counter-val [v id] (letfn [(inc-email [m k v] (assoc m k (inc v)))] (update-in v [id :email] #(reduce-kv inc-email {} %)))) (defn update-counter [id xs] (dosync (alter xs update-counter-val id))) (dotimes [_ 3] (update-counter 3 example)) @example (note : this example is a little bit more general: it increments each value of each email found in the map under the :email key) finally, if there is only one email per record, then maybe the structure of the record should be simplified (and the resulting code) as such: => (require '[clojure.set :as s]) (def example (ref {1 {:id 1 :email "a...@mail.com" :email-occurences 1} 2 {:id 2 :email "d...@mail.com" :email-occurences 1} 3 {:id 3 :email "g...@mail.com" :email-occurences 2} 4 {:id 4 :email "f...@mail.com" :email-occurences 2}})) (defn update-counter-val [v id] (update-in v [id :email-occurences] inc)) (defn update-counter [id xs] (dosync (alter xs update-counter-val id))) (dotimes [_ 3] (update-counter 3 example)) @example nil #'user/example #'user/update-counter-val #'user/update-counter nil {1 {:email-occurences 1, :email "a...@mail.com", :id 1}, 2 {:email-occurences 1, :email "d...@mail.com", :id 2}, 3 {:email-occurences 5, :email "g...@mail.com", :id 3}, 4 {:email-occurences 2, :email "f...@mail.com", :id 4}} At this point, it becomes arguable, again, if update-counter-val should exist on its own. Inlining it again inside update-counter then gives: => (require '[clojure.set :as s]) (def example (ref {1 {:id 1 :email "a...@mail.com" :email-occurences 1} 2 {:id 2 :email "d...@mail.com" :email-occurences 1} 3 {:id 3 :email "g...@mail.com" :email-occurences 2} 4 {:id 4 :email "f...@mail.com" :email-occurences 2}})) (defn update-counter [id xs] (dosync (alter xs update-in [id :email-occurences] inc))) (dotimes [_ 3] (update-counter 3 example)) @example nil #'user/example #'user/update-counter nil {1 {:email-occurences 1, :email "a...@mail.com", :id 1}, 2 {:email-occurences 1, :email "d...@mail.com", :id 2}, 3 {:email-occurences 5, :email "g...@mail.com", :id 3}, 4 {:email-occurences 2, :email "f...@mail.com", :id 4}} HTH, -- Laurent 2013/6/12 Kelker Ryan <theinter...@yandex.com>: > Here's the refactored version. > > user> (def example > (ref > [{:id 1 :email {"a...@mail.com" 1}} > {:id 2 :email {"d...@mail.com" 1}} > {:id 3 :email {"g...@mail.com" 2}} > {:id 4 :email {"f...@mail.com" 2}}])) > #'user/example > user> > (defn update-counter [id xs] > (dosync > (let [_ @xs > at-after (drop-while #(not= id (:id %)) _) > mod-key (-> at-after first :email keys first) > location (- (count _) (count at-after))] > (alter xs update-in [location :email mod-key] inc)))) > #'user/update-counter > user> (dotimes [_ 3] > (update-counter 3 example)) > nil > user> (clojure.pprint/pprint @example) > [{:email {"a...@mail.com" 1}, :id 1} > {:email {"d...@mail.com" 1}, :id 2} > {:email {"g...@mail.com" 5}, :id 3} > {:email {"f...@mail.com" 2}, :id 4}] > nil > > > > > 12.06.2013, 14:47, "Meikel Brandmeyer (kotarak)" <m...@kotka.de>: > > Hi, > > Am Mittwoch, 12. Juni 2013 06:39:59 UTC+2 schrieb Kelker Ryan: > > user> (defn update-counter [id xs] > > (let [at-after (drop-while #(not= id (:id %)) @xs) > to-modify (-> at-after first :email) > mod-key (-> to-modify keys first) > location (let [_ (- (count @xs) (count at-after))] > (if-not (pos? _) 0 _))] > (dosync > (alter xs update-in [location :email mod-key] inc)))) > > > You have to wrap all accesses to xs in the same dosync. > > Kind regards > Meikel > > > -- > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > > -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.