Re: alter a map in a vector (reference)
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
Re: alter a map in a vector (reference)
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)" :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 regardsMeikel -- -- 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.
Re: alter a map in a vector (reference)
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.
Re: alter a map in a vector (reference)
I've seen some interesting responses, but here's my solution. 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] (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 #'user/update-counter user> (update-counter 4 example) -- output removed -- user> (update-counter 1 example) -- output removed -- user> (clojure.pprint/pprint @example) [{:email {"a...@mail.com" 2}, :id 1} {:email {"d...@mail.com" 1}, :id 2} {:email {"g...@mail.com" 2}, :id 3} {:email {"f...@mail.com" 3}, :id 4}] nil 12.06.2013, 11:19, "Yoshinori Kohyama" : > Solutions seem to depend on whether you have two or more mail addresses in a ':emails' section or not.> If you have, you should identify the mail address of which you want to increment the value.> Anyway, try below:>> (dosync> (alter result> (fn [v]> (mapv second> (update-in (into {} (map #(vector (:id %) %) v))> [1 :emails "a...@mail.com"]> inc)>> HTH,> with regards,> Yoshinori Kohyama>> --> --> 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.
Re: alter a map in a vector (reference)
Solutions seem to depend on whether you have two or more mail addresses in a ':emails' section or not. If you have, you should identify the mail address of which you want to increment the value. Anyway, try below: (dosync (alter result (fn [v] (mapv second (update-in (into {} (map #(vector (:id %) %) v)) [1 :emails "a...@mail.com"] inc) HTH, with regards, Yoshinori Kohyama -- -- 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.
Re: alter a map in a vector (reference)
You *can* update this inside the vector, but if you want to key by :id, I would personally recommend, you put the email data into a map and look it up by :id, like this: {1 {:id 1 :email {"a...@mail.com 1}} 2 {:id 2 :email {"d...@mail.com 1}} 3 {:id 3 :email {"g...@mail.com 2}}} Best, Alex On Mon, Jun 3, 2013 at 1:44 PM, Yinka Erinle wrote: > Thanks Meikel for the prompt reply, that does it. > > Please can you elaborate on how I can use the solution below to update a > particular entry in the vector. > > [{:id 1 :email {"a...@mail.com 1}} > {:id 2 :email {"d...@mail.com 1}} > {:id 3 :email {"g...@mail.com 2}}] > > So I will like to write a function that accepts an id and then updates the > counter in email section of the given id. > > (defn update-counter [x xs] >(dosync > (alter result .. > > Thanks again for your time. > > > On Monday, June 3, 2013 9:23:47 PM UTC+1, Meikel Brandmeyer (kotarak) > wrote: >> >> Hi, >> >> Am Montag, 3. Juni 2013 22:16:54 UTC+2 schrieb Yinka Erinle: >>> >>> Given I have the following >>> (def result (ref [ { :id 1 :emails { "yi...@mail.com" 1}} ] ) ) >>> >>> I like to alter the result in a transaction to become >>> [{:id 1 :emails { "yi...@mail.com" 2}}]; increment the counter from >>> 1 to 2 >>> >>> Please can someone provide pointers. >>> >>> >> You can use the uniform update principle to stitch together alter and >> update-in. >> >> (dosync >> (alter result update-in [0 :emails "a@b.c"] inc)) >> >> 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.
Re: alter a map in a vector (reference)
Thanks Meikel for the prompt reply, that does it. Please can you elaborate on how I can use the solution below to update a particular entry in the vector. [{:id 1 :email {"a...@mail.com 1}} {:id 2 :email {"d...@mail.com 1}} {:id 3 :email {"g...@mail.com 2}}] So I will like to write a function that accepts an id and then updates the counter in email section of the given id. (defn update-counter [x xs] (dosync (alter result .. Thanks again for your time. On Monday, June 3, 2013 9:23:47 PM UTC+1, Meikel Brandmeyer (kotarak) wrote: > > Hi, > > Am Montag, 3. Juni 2013 22:16:54 UTC+2 schrieb Yinka Erinle: >> >> Given I have the following >> (def result (ref [ { :id 1 :emails { "yi...@mail.com" 1}} ] ) ) >> >> I like to alter the result in a transaction to become >> [{:id 1 :emails { "yi...@mail.com" 2}}]; increment the counter from >> 1 to 2 >> >> Please can someone provide pointers. >> >> > You can use the uniform update principle to stitch together alter and > update-in. > > (dosync > (alter result update-in [0 :emails "a@b.c"] inc)) > > 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.
Re: alter a map in a vector (reference)
Hi, Am Montag, 3. Juni 2013 22:16:54 UTC+2 schrieb Yinka Erinle: > > Given I have the following > (def result (ref [ { :id 1 :emails { "yi...@mail.com " 1}} ] > ) ) > > I like to alter the result in a transaction to become > [{:id 1 :emails { "yi...@mail.com " 2}}]; increment the > counter from 1 to 2 > > Please can someone provide pointers. > > You can use the uniform update principle to stitch together alter and update-in. (dosync (alter result update-in [0 :emails "a@b.c"] inc)) 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.
alter a map in a vector (reference)
Hi, I struggling to find a way to alter a value in a map that resides in a vector. Given I have the following (def result (ref [ { :id 1 :emails { "yi...@mail.com" 1}} ] ) ) I like to alter the result in a transaction to become [{:id 1 :emails { "yi...@mail.com" 2}}]; increment the counter from 1 to 2 Please can someone provide pointers. Thanks, Yinka. -- -- 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.