(newbie) replace certain values of a map based on a predicate

751 views
Skip to first unread message

Colin Yates

unread,
Jul 5, 2013, 4:59:54 PM7/5/13
to clo...@googlegroups.com
Hi all,

I think this is one of those questions which has quite a few answers, but given a map, how do I replace the values by applying a function to those values, but only if they meet a condition?

I understand the building blocks of (map..), (filter..), (assoc-in..) and (filter..) and I can see how something could work using those pieces but is would be pretty verbose.  I am sure there is probably a much more simple way using a more abstract function.

The actual use case is I have a list of maps as returned from the clojure.java.jdbc framework and they contain timestamps.  I want to replace all the timestamps with (for example) to a Joda LocalDate using the excellent clj-time library.

Any pointers?

Thanks!

Col

John Walker

unread,
Jul 5, 2013, 5:08:00 PM7/5/13
to clo...@googlegroups.com
I had to do something similar, and used clojure.walk.

Jim - FooBar();

unread,
Jul 5, 2013, 5:14:01 PM7/5/13
to clo...@googlegroups.com
You'll never really 'replace' any values so why not reduce/reduce-kv ?
Just build a new map out of the old one...

Jim
> --
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@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+u...@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+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Jay Fields

unread,
Jul 5, 2013, 5:15:43 PM7/5/13
to clo...@googlegroups.com
I use update-vals from https://github.com/jaycfields/jry fairly often. As long as you don't mind doing the pred check in the fn you pass to update-vals, it should do the trick.

Cheers, Jay


On Fri, Jul 5, 2013 at 5:14 PM, Jim - FooBar(); <jimpi...@gmail.com> wrote:
You'll never really 'replace' any values so why not reduce/reduce-kv ? Just build a new map out of the old one...

Jim


On 05/07/13 21:59, Colin Yates wrote:
Hi all,

I think this is one of those questions which has quite a few answers, but given a map, how do I replace the values by applying a function to those values, but only if they meet a condition?

I understand the building blocks of (map..), (filter..), (assoc-in..) and (filter..) and I can see how something could work using those pieces but is would be pretty verbose.  I am sure there is probably a much more simple way using a more abstract function.

The actual use case is I have a list of maps as returned from the clojure.java.jdbc framework and they contain timestamps.  I want to replace all the timestamps with (for example) to a Joda LocalDate using the excellent clj-time library.

Any pointers?

Thanks!

Col
--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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

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+unsubscribe@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 clo...@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

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+unsubscribe@googlegroups.com.

Jim - FooBar();

unread,
Jul 5, 2013, 5:22:11 PM7/5/13
to clo...@googlegroups.com
I 'd change the implentation of update-vals to use reduce-kv. you will avoid the cost of destructuring on every single step :)

Jim




On 05/07/13 22:15, Jay Fields wrote:
I use update-vals from https://github.com/jaycfields/jry fairly often. As long as you don't mind doing the pred check in the fn you pass to update-vals, it should do the trick.

Cheers, Jay
On Fri, Jul 5, 2013 at 5:14 PM, Jim - FooBar(); <jimpi...@gmail.com> wrote:
You'll never really 'replace' any values so why not reduce/reduce-kv ? Just build a new map out of the old one...

Jim


On 05/07/13 21:59, Colin Yates wrote:
Hi all,

I think this is one of those questions which has quite a few answers, but given a map, how do I replace the values by applying a function to those values, but only if they meet a condition?

I understand the building blocks of (map..), (filter..), (assoc-in..) and (filter..) and I can see how something could work using those pieces but is would be pretty verbose.  I am sure there is probably a much more simple way using a more abstract function.

The actual use case is I have a list of maps as returned from the clojure.java.jdbc framework and they contain timestamps.  I want to replace all the timestamps with (for example) to a Joda LocalDate using the excellent clj-time library.

Any pointers?

Thanks!

Col
--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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

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+u...@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 clo...@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

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+u...@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 clo...@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

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+u...@googlegroups.com.

Colin Yates

unread,
Jul 5, 2013, 5:29:31 PM7/5/13
to clo...@googlegroups.com
Grrr.. google groups seems to be playing up so apologies if this is double posted.

Thanks both!

My attempt (inspired by Stuart Sierra's reply at https://groups.google.com/forum/#!topic/clojure/Hlfn4PdKg-k) was something like this (from memory so forgive me):

(defn val-or-date [result [k v]] (if (instance? java.sql.Date v) (assoc result k (local-time/to-local-date-time v)) (assoc result k v)))
(reduce val-or-date {} r)

I can see how val-or-date can be much more generic passing in a predicate and transformation function, sure.

Col

On Friday, 5 July 2013 22:15:43 UTC+1, Jay Fields wrote:
I use update-vals from https://github.com/jaycfields/jry fairly often. As long as you don't mind doing the pred check in the fn you pass to update-vals, it should do the trick.

Cheers, Jay
On Fri, Jul 5, 2013 at 5:14 PM, Jim - FooBar(); <jimpi...@gmail.com> wrote:
You'll never really 'replace' any values so why not reduce/reduce-kv ? Just build a new map out of the old one...

Jim


On 05/07/13 21:59, Colin Yates wrote:
Hi all,

I think this is one of those questions which has quite a few answers, but given a map, how do I replace the values by applying a function to those values, but only if they meet a condition?

I understand the building blocks of (map..), (filter..), (assoc-in..) and (filter..) and I can see how something could work using those pieces but is would be pretty verbose.  I am sure there is probably a much more simple way using a more abstract function.

The actual use case is I have a list of maps as returned from the clojure.java.jdbc framework and they contain timestamps.  I want to replace all the timestamps with (for example) to a Joda LocalDate using the excellent clj-time library.

Any pointers?

Thanks!

Col
--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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

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+u...@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 clo...@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

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+u...@googlegroups.com.

Ben Wolfson

unread,
Jul 5, 2013, 5:31:05 PM7/5/13
to clo...@googlegroups.com
You could use clojure.algo.generic.functor.fmap: (fmap #(if (pred? %) replacement-value %) your-map).


--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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+u...@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+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Ben Wolfson
"Human kind has used its intelligence to vary the flavour of drinks, which may be sweet, aromatic, fermented or spirit-based. ... Family and social life also offer numerous other occasions to consume drinks for pleasure." [Larousse, "Drink" entry]

Cedric Greevey

unread,
Jul 5, 2013, 5:51:40 PM7/5/13
to clo...@googlegroups.com
Even without reaching for libraries outside clojure.core, there's

(update-in m [:key-of-interest] #(if (condition? %) (transformation %) %))

and the ability to convert that into a function, e.g.

(defn conditional-update-in [m condition? transformation k]
  (update-in m [k] #(if (condition? %) (transformation %) %)))

and then, if you have many keys that should undergo the same transformation under the same condition,

(reduce (partial conditional-update-in m condition? transformation) [keys...]), and its encapsulation,

(defn conditional-update-multi [m condition? transformation ks]
  (reduce (partial conditional-update-in m condition? transformation) ks))


Justin Kramer

unread,
Jul 5, 2013, 6:07:15 PM7/5/13
to clo...@googlegroups.com
Besides post-processing results, you can also instruct java.jdbc to return Joda dates in the first place.

Using clojure.java.jdbc 0.3.0-alpha4:

(ns example
  (:require [clojure.java.jdbc :as j]
            [clj-time.local :as cl]))
...
(extend-protocol j/IResultSetReadColumn
  java.sql.Date
  (result-set-read-column [date]
    (cl/to-local-date-time date)))

Note that result-set-read-column's signature has changed in master; you'll need to update it to [date _ _] in the next release.

Justin

Colin Yates

unread,
Jul 12, 2013, 3:54:37 AM7/12/13
to clo...@googlegroups.com

Thanks Cedric,

I am constantly writing code and then finding something in the core library whivh already does what I need :). 

http://clojuredocs.org/clojure_core/1.2.0/clojure.walk/keywordize-keys was the latest gem.

You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/Wqu-VBR5bSk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages