Re: alter a map in a vector (reference)

2013-06-12 Thread Laurent PETIT
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)

2013-06-11 Thread Kelker Ryan
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)

2013-06-11 Thread 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 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)

2013-06-11 Thread Kelker Ryan
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)

2013-06-11 Thread 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.




Re: alter a map in a vector (reference)

2013-06-03 Thread Alex Baranosky
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)

2013-06-03 Thread Yinka Erinle
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)

2013-06-03 Thread Meikel Brandmeyer (kotarak)
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)

2013-06-03 Thread Yinka Erinle
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.