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

Reply via email to