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

Reply via email to