Hi, I have come across use cases in the past where an additional transformation step was indeed very handy and I wrote my own version of group-by, one identical to Daniel's.
Maybe a function worthwhile for c.c.incubator. Las 2012/12/17 Daniel Dinnyes <dinny...@gmail.com> > Also note that I wrote in my first post that "Without the value-mapper > argument it is very awkward to achieve the same structure after the > group-by call". The `map-vals` function is almost the closest you can get > to map values after a group-by in a streamlined and clean manner. There is ` > fmap<http://clojuredocs.org/clojure_contrib/clojure.contrib.generic.functor/fmap>` > in the contrib which does a similar thing already though. > > An even cleaner mapper would be something like a `map-multi-vals`, so that > you can do something like this: > > (->> (group-by :type animals) > (map-multi-vals :name)) > > That's the cleanest one can get with a separate value-mapper. In my > opinion that has little added benefit though, and possibly the performance > is worse too. The only benefit would be separation of concern: you can map > values of a multi-map without knowing how it was created. Now think about > it: how often would you use `map-multi-vals` separately, not right after a > group-by? My impression is that whenever an multi-map is created, it almost > always involves in some way a `group-by` - which itself is a special case > of `reduce`. There is always a `reduce` somewhere, whether an `into`, a > `for`, or some imperative iteration. Only `group-by` is the simplest for > this specific purpose of creating a multi-map. > > My argument therefore is that whenever you need a multi-value mapping, it > is always preceded by a group-by, and therefore I feel the right place for > the value-mapper is as an optional parameter for `group-by` itself. > > What do you think? > > Cheers, > Daniel > > > On Monday, December 17, 2012 10:13:17 AM UTC, Daniel Dinnyes wrote: >> >> Hi, >> >> I expect the cost of calling `identity` to be negligible. Not for sure, >> but the JVM might even inline it at run-time, or there might be >> optimizations for it in clojure.core during compilation... I cannot comment >> on that. But even with a full virtual call, it should be faster than >> iterating the whole map again. >> >> Also, that `map-vals` is still indeed clunkier ;) Different usages, but >> for me whenever I use `group-by` I very often find I prefer to map the >> values too (to get a nice streamlined data structure to be passed around >> for further processing). Just my experience. It was very handy in .NET, and >> I think it was there for this reason. >> >> Regards, >> Daniel >> >> On Monday, December 17, 2012 8:21:44 AM UTC, Alex Baranosky wrote: >>> >>> I haven't run into this issue (yet). My first devil's advocate thought >>> was to suggest that you could map over the data after calling the group-by. >>> >>> (->> (group-by :type animals) >>> (map-vals #(map :name %))) >>> >>> There are two problems with this. One, it uses a custom util function >>> `map-vals` so it is a bit of a cheat. Two, even with that it still looks >>> pretty clunky. >>> >>> How does the `identity` effect performance? I wouldn't think much. >>> >>> Alex >>> >>> On Fri, Dec 14, 2012 at 9:58 AM, Daniel Dinnyes <dinn...@gmail.com>wrote: >>> >>>> Hi, >>>> >>>> I would like to suggest an enhancement to the clojure.core/group-by >>>> function. The idea came from using Enumerable.GroupBy >>>> <http://msdn.microsoft.com/en-us/library/bb534304.aspx>extension >>>> method in .NET quite much. It is really handy to have an optional >>>> value-mapper function which transforms the elements before adding them to >>>> the collection under the key. It is backward compatible, because calling >>>> the overload with 2 parameters can call the 3 parameter one with >>>> clojure.corj/identity as value-mapper function. >>>> >>>> The implementation is easy-peasy (almost the same as the original): >>>> >>>> (defn group-by >>>> ([f g coll] >>>> (persistent! >>>> (reduce >>>> (fn [ret x] >>>> (let [k (f x)] >>>> (assoc! ret k (conj (get ret k []) (g x))))) >>>> (transient {}) coll))) >>>> ([f coll] >>>> (group-by f identity coll))) >>>> >>>> Without the value-mapper argument it is very awkward to achieve the >>>> same structure after the group-by call. Also, doing the transformation >>>> before the group-by is often impossible, because the key function depends >>>> on some property of the source element, which would be removed after the >>>> transformation. >>>> >>>> To demonstrate the usage, check out the below calls: >>>> >>>> (def animals [{:name "Betsy" :type :cow} >>>> {:name "Murmur" :type :cat} >>>> {:name "Lessie" :type :dog} >>>> {:name "Dingo" :type :dog} >>>> {:name "Rosie" :type :cat} >>>> {:name "Rex" :type :dog} >>>> {:name "Alf" :type :cat}]) >>>> >>>> (group-by :type animals) ; old usage >>>> > ... ugly stuff >>>> >>>> (group-by :type :name animals) ; new usage >>>> > {:cow ["Betsy"], :cat ["Murmur" "Rosie" "Alf"], :dog ["Lessie" >>>> "Dingo" "Rex"]} >>>> >>>> (group-by :type #(.toUpperCase (:name %)) animals) ; hell yeah! >>>> > {:cow ["BETSY"], :cat ["MURMUR" "ROSIE" "ALF"], :dog ["LESSIE" >>>> "DINGO" "REX"]} >>>> >>>> It would be so cool to have this in the core. What do you guys think? >>>> >>>> Regards, >>>> Daniel Dinnyes >>>> >>>> -- >>>> 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<http://groups.google.com/group/clojure?hl=en> >>> >>> >>> -- > 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 > -- László Török -- 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