I think it sounds like a nice addition, after mulling it over a little. On Mon, Dec 17, 2012 at 4:47 AM, László Török <ltoro...@gmail.com> wrote:
> 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 > -- 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