Re: Mapping a function over a map's values
Awesome. Thanks Konrad. On Mar 23, 4:11 am, Konrad Hinsen konrad.hin...@laposte.net wrote: On 22.03.2009, at 21:10, Jon Nadal wrote: I often need to map a function over the values of a map while preserving keys--something like: ... Is there a more concise way to do this in Clojure? If not, is this something that might be worth putting in the contrib? Look at clojure.contrib.generic.functor/fmap. It does what you need for maps, for all the other Clojure collections (where it works like map except that its return value is a collection of the same type as the input value), and you can implement it for any type you define yourself, e.g. a tree structure. Konrad. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Sun, 22 Mar 2009 at 23:27, Jeff Valk wrote: Ah, golf... :-) (defn mapmap [f m] (into {} (for [[k v] m] [k (f v)]))) For the record, I think the original approach is the most clear. And it's actually shorter. (defn mapmap [f m] (zipmap (keys m) (map f (vals m --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On 22.03.2009, at 21:10, Jon Nadal wrote: I often need to map a function over the values of a map while preserving keys--something like: ... Is there a more concise way to do this in Clojure? If not, is this something that might be worth putting in the contrib? Look at clojure.contrib.generic.functor/fmap. It does what you need for maps, for all the other Clojure collections (where it works like map except that its return value is a collection of the same type as the input value), and you can implement it for any type you define yourself, e.g. a tree structure. Konrad. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Sun, Mar 22, 2009 at 11:53 PM, Jeff Valk jv-li...@tx.rr.com wrote: For the record, I think the original approach is the most clear. And it's actually shorter. (defn mapmap [f m] (zipmap (keys m) (map f (vals m But it traverses m twice, which is likely to be less efficient. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Mon, Mar 23, 2009 at 3:11 AM, Konrad Hinsen konrad.hin...@laposte.net wrote: On 22.03.2009, at 21:10, Jon Nadal wrote: I often need to map a function over the values of a map while preserving keys--something like: ... Is there a more concise way to do this in Clojure? If not, is this something that might be worth putting in the contrib? Look at clojure.contrib.generic.functor/fmap. It does what you need for maps, for all the other Clojure collections (where it works like map except that its return value is a collection of the same type as the input value), and you can implement it for any type you define yourself, e.g. a tree structure. This has methods for IPersistentVector, IPersistentSet, IPersistentMap and ISeq. Why isn't there a method for IPersistentList? -- R. Mark Volkmann Object Computing, Inc. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Mar 23, 2009, at 12:15, Mark Volkmann wrote: Look at clojure.contrib.generic.functor/fmap. It does what you need for maps, for all the other Clojure collections (where it works like map except that its return value is a collection of the same type as the input value), and you can implement it for any type you define yourself, e.g. a tree structure. This has methods for IPersistentVector, IPersistentSet, IPersistentMap and ISeq. Why isn't there a method for IPersistentList? Oversight. I'll add it! That leaves the question whether there is still any need for the clojure.lang.ISeq implementation. At the moment it is used for lists, but that is not particularly consistent. I guess I will remove it. Konrad. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
I prefer the into version which allows to write a mapmap that preserves the map type (eg sorted or hash): (defn mapmap [f m] (into (empty m) (for [[k v] m] [k (f v)]))) Christophe On Mon, Mar 23, 2009 at 7:53 AM, Jeff Valk jv-li...@tx.rr.com wrote: On Sun, 22 Mar 2009 at 23:27, Jeff Valk wrote: Ah, golf... :-) (defn mapmap [f m] (into {} (for [[k v] m] [k (f v)]))) For the record, I think the original approach is the most clear. And it's actually shorter. (defn mapmap [f m] (zipmap (keys m) (map f (vals m --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Mon, Mar 23, 2009 at 7:04 AM, Konrad Hinsen konrad.hin...@laposte.net wrote: On Mar 23, 2009, at 12:15, Mark Volkmann wrote: Look at clojure.contrib.generic.functor/fmap. It does what you need for maps, for all the other Clojure collections (where it works like map except that its return value is a collection of the same type as the input value), and you can implement it for any type you define yourself, e.g. a tree structure. This has methods for IPersistentVector, IPersistentSet, IPersistentMap and ISeq. Why isn't there a method for IPersistentList? Oversight. I'll add it! That leaves the question whether there is still any need for the clojure.lang.ISeq implementation. At the moment it is used for lists, but that is not particularly consistent. I guess I will remove it. Maybe you should keep it to support custom kinds of sequences that implement ISeq, but not one of the other interfaces like IPersistentList. -- R. Mark Volkmann Object Computing, Inc. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Mar 23, 2009, at 14:26, Mark Volkmann wrote: That leaves the question whether there is still any need for the clojure.lang.ISeq implementation. At the moment it is used for lists, but that is not particularly consistent. I guess I will remove it. Maybe you should keep it to support custom kinds of sequences that implement ISeq, but not one of the other interfaces like IPersistentList. Among the built-in data types, none does as far as I know. Those who implement new data types with ISeq should also provide an implementation for fmap, in order to make sure that the return type is right and that the semantics are right as well. For example, maps implement ISeq, but a default implementation for ISeq would not be correct for maps. Konrad. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Mon, 23 Mar 2009 at 03:29, Mark Engelberg wrote: But it traverses m twice, which is likely to be less efficient. I wondered about this too, and actually no. Zipmap is efficient. It constructs its return map in a single loop from two lazy seqs. Performance is practically identical to the for version: (defn mapmap1 [f m] (into {} (for [[k v] m] [k (f v)]))) (defn mapmap2 [f m] (zipmap (keys m) (map f (vals m (def m (apply hash-map (range 200))) (time (def m2 (mapmap1 identity m))) Elapsed time: 3221.625654 msecs (time (def m2 (mapmap2 identity m))) Elapsed time: 3322.947888 msecs --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Mon, 23 Mar 2009 at 07:57, Christophe Grand wrote: I prefer the into version which allows to write a mapmap that preserves the map type (eg sorted or hash): (defn mapmap [f m] (into (empty m) (for [[k v] m] [k (f v)]))) Agreed. If it were in contrib, this would make most sense. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Mar 23, 2009, at 16:36, Jeff Valk wrote: I prefer the into version which allows to write a mapmap that preserves the map type (eg sorted or hash): (defn mapmap [f m] (into (empty m) (for [[k v] m] [k (f v)]))) Agreed. If it were in contrib, this would make most sense. It is already in clojure.contrib, with exactly that implementation, and for exactly that reason: http://code.google.com/p/clojure-contrib/source/browse/trunk/src/ clojure/contrib/generic/functor.clj Konrad. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Mon, 23 Mar 2009 at 10:48, Konrad Hinsen wrote: It is already in clojure.contrib, with exactly that implementation, and for exactly that reason: Well I'm glad we agree then. :-) And thanks for the pointer. -Jeff --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Mar 23, 2009, at 5:24 AM, Jeff Valk wrote: On Mon, 23 Mar 2009 at 03:29, Mark Engelberg wrote: But it traverses m twice, which is likely to be less efficient. I wondered about this too, and actually no. I think Mark was referring to the call to 'keys'. But apparently Clojure doesn't need to traverse the map to generate the keys? Zipmap is efficient. It constructs its return map in a single loop from two lazy seqs. Not sure what you mean here. It will produce a map from any 2 seqs. And it does not generate it lazily--it uses loop. Don't try this at home: (zipmap (map str (iterate inc 1)) (iterate inc 1)) Aloha, David Sletten --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
On Mon, 23 Mar 2009 at 20:10, David Sletten wrote: I think Mark was referring to the call to 'keys'. But apparently Clojure doesn't need to traverse the map to generate the keys? The call to keys just creates a seq. There's no traversal until you consume it. Not sure what you mean here. It will produce a map from any 2 seqs. And it does not generate it lazily--it uses loop. Don't try this at home: (zipmap (map str (iterate inc 1)) (iterate inc 1)) Indeed that's a good one to avoid. :-) I simply meant that *in the keys/vals example above*, using zipmap is approximately as efficient (in time and space) as for or reduce, a result I found interesting. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
(defn mapmap [fn m] (into {} (map #(vector (first %) (fn (second %))) m))) On Sun, Mar 22, 2009 at 1:10 PM, Jon Nadal jon.na...@gmail.com wrote: I often need to map a function over the values of a map while preserving keys--something like: [code] (defn mapmap [fn m] (let [k (keys m) v (map fn (vals m))] (zipmap k v))) (mapmap inc {:a 0, :b 1}) [/code] Is there a more concise way to do this in Clojure? If not, is this something that might be worth putting in the contrib? -Jon -- And what is good, Phaedrus, And what is not good— Need we ask anyone to tell us these things? --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Mapping a function over a map's values
Golf time! (defn mapmap [f m] (into {} (map (fn [[x y]] [x (f y)]) m))) On Mar 23, 2:51 pm, Kevin Downey redc...@gmail.com wrote: (defn mapmap [fn m] (into {} (map #(vector (first %) (fn (second %))) m))) --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---