I like the idea of it being built-in and might prefer that approach, however, I wanted to share an alternative.
https://gist.github.com/4346395 I needed to take a denormalized table of config data and create a nested lookup map, so that I wouldn't need to repeatedly filter the dataset while using it to process a stream of data. On Monday, December 17, 2012 3:20:32 PM UTC-6, Alex Baranosky wrote: > > 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 <ltor...@gmail.com<javascript:> > > 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 <dinn...@gmail.com <javascript:>> >> >>> 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 clo...@googlegroups.com<javascript:> >>> 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 <javascript:> >>> 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 clo...@googlegroups.com<javascript:> >> 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 <javascript:> >> 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