Groovy2 shorthand for: collect{}.flatten()

classic Classic list List threaded Threaded
77 messages Options
1234 ... 8
Reply | Threaded
Open this post in threaded view
|

Groovy2 shorthand for: collect{}.flatten()

Jon Cox


  Most of the time, if I'm creating sublists within a collect(),
  what I'm really doing is combined grep+transform operation on
  the original list.  

  In Groovy, saying:       mylist.collect { ... }.flatten()
  is like saying in Perl:  map { ... } @mylist

  It would be convenient if groovy had a built-in
  auto-flattening version of collect too.


  //------------------------------------------------------------------
  // Example:
    def bar = [1,2,3].collect{(it%2) ? it*5 : []}.flatten() // [5,15]

   
  // could become:
    def bar = [1,2,3].map{(it%2) ? it*5 : []}               // [5,15]

  //------------------------------------------------------------------


  Perhaps calling it 'map' might be confusing to some people, given
  the fact that groovy/java has a Map structure, but maybe not.
  I hope not (it's so easy to type), but if the feature seems
  appealing yet the name isn't, please suggest one.
   
  Currently, I type 19 chars of code text  (i.e.: "collect{}.flatten()")
  compared to only   5 chars of code text  (i.e.: "map{}")
  with the map{} proposal.

  Another benefit is that the map{} shorthand makes the
  intent of the code stand out better.
 
  There's nothing wrong with non-flattening collect(),
  but filter+modify does come up a lot as a "single intent".  
  Hence, every time I need to collect(){}.flatten(), I think:  
  "I wish Groovy had a built-in for that".

  Does this sound reasonable feature request, and is map{} an
  acceptable name?  I'll file it in JIRA if the general
  feedback seems positive.


                Cheers,
                -Jon

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Groovy2 shorthand for: collect{}.flatten()

paulk_asert

Something similar to this has been discussed before:
http://jira.codehaus.org/browse/GROOVY-3526

But something that could use closure composition or currying
might prove more general purpose.

Cheers, Paul.

On 8/06/2011 12:39 PM, Jon Cox wrote:

>
>
>    Most of the time, if I'm creating sublists within a collect(),
>    what I'm really doing is combined grep+transform operation on
>    the original list.
>
>    In Groovy, saying:       mylist.collect { ... }.flatten()
>    is like saying in Perl:  map { ... } @mylist
>
>    It would be convenient if groovy had a built-in
>    auto-flattening version of collect too.
>
>
>    //------------------------------------------------------------------
>    // Example:
>      def bar = [1,2,3].collect{(it%2) ? it*5 : []}.flatten() // [5,15]
>
>
>    // could become:
>      def bar = [1,2,3].map{(it%2) ? it*5 : []}               // [5,15]
>
>    //------------------------------------------------------------------
>
>
>    Perhaps calling it 'map' might be confusing to some people, given
>    the fact that groovy/java has a Map structure, but maybe not.
>    I hope not (it's so easy to type), but if the feature seems
>    appealing yet the name isn't, please suggest one.
>
>    Currently, I type 19 chars of code text  (i.e.: "collect{}.flatten()")
>    compared to only   5 chars of code text  (i.e.: "map{}")
>    with the map{} proposal.
>
>    Another benefit is that the map{} shorthand makes the
>    intent of the code stand out better.
>
>    There's nothing wrong with non-flattening collect(),
>    but filter+modify does come up a lot as a "single intent".
>    Hence, every time I need to collect(){}.flatten(), I think:
>    "I wish Groovy had a built-in for that".
>
>    Does this sound reasonable feature request, and is map{} an
>    acceptable name?  I'll file it in JIRA if the general
>    feedback seems positive.
>
>
>                  Cheers,
>                  -Jon
>
> ---------------------------------------------------------------------
> To unsubscribe from this list, please visit:
>
>      http://xircles.codehaus.org/manage_email
>
>
>


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Groovy2 shorthand for: collect{}.flatten()

Jon Cox

 Paul,
   
  Thanks for referencing GROOVY-3526.
  If/when I file a JIRA, I'll cross link these requests.

  Overview of my remarks:
   
   (1)  Both eliding and augmenting the list are supported by map
   (2)  Groovy makes this harder than other languages (perl,ruby)
   (3)  A terse shorthand makes this code easier to read/write.
   (4)  map{} looks more powerful/standard/compact than GROOVY-3526


  See below for gory details.


> On 8/06/2011 12:39 PM, Jon Cox wrote:
>>    Most of the time, if I'm creating sublists within a collect(),
>>    what I'm really doing is combined grep+transform operation on
>>    the original list.
>>
>>    In Groovy, saying:       mylist.collect { ... }.flatten()
>>    is like saying in Perl:  map { ... } @mylist
>>
>>    It would be convenient if groovy had a built-in
>>    auto-flattening version of collect too.
>>
>>    //------------------------------------------------------------------
>>    // Example:
>>      def bar = [1,2,3].collect{(it%2) ? it*5 : []}.flatten() // [5,15]
>>
>>    // could become:
>>      def bar = [1,2,3].map{(it%2) ? it*5 : []}               // [5,15]
>>    //------------------------------------------------------------------
>>
>>    Perhaps calling it 'map' might be confusing to some people, given
>>    the fact that groovy/java has a Map structure, but maybe not.
>>    I hope not (it's so easy to type), but if the feature seems
>>    appealing yet the name isn't, please suggest one.
>>
>>    Currently, I type 19 chars of code text  (i.e.: "collect{}.flatten()")
>>    compared to only   5 chars of code text  (i.e.: "map{}")
>>    with the map{} proposal.
>>
>>    Another benefit is that the map{} shorthand makes the
>>    intent of the code stand out better.
>>
>>    There's nothing wrong with non-flattening collect(),
>>    but filter+modify does come up a lot as a "single intent".
>>    Hence, every time I need to collect(){}.flatten(), I think:
>>    "I wish Groovy had a built-in for that".
>>
>>    Does this sound reasonable feature request, and is map{} an
>>    acceptable name?  I'll file it in JIRA if the general
>>    feedback seems positive.
>>
>>
* Paul King ([hidden email]) [110607 20:19]:
>
> Something similar to this has been discussed before:
> http://jira.codehaus.org/browse/GROOVY-3526
>
> But something that could use closure composition or currying
> might prove more general purpose.

   
  If I'm understanding GROOVY-3526 properly, 'condition'
  is grep-like pre-filter, and 'transform' is a simple
  scalar-to-scalar mapping (not scalar-to-list).

  Aside:   I think Ted Naleid's comments on GROOVY-3526
           aren't trying to handle either list reduction
           or augmentation.  Other languages do handle
           this, and I think Groovy should.

  The map{} semantics I've cribbed from perl let you do
  more than just grep+transform.  If you want, you can
  grep + transform + *augment* too (which comes in handy).

  Therefore, GROOVY-3526 looks somewhat more verbose for the
  common case, and a bit less powerful than map{} overall.

  Consider:

    //-------------------------------------------------------
    // Selectively transform & augment list:  [1,2,3]
    //
    def bar = [1,2,3].map{(it % 2) ? (it*=5) : [it*500,"hi"]}
    assert bar == [5,1000,"hi",15]
    //-------------------------------------------------------


  Because map auto-flattens its result, you always just end up
  with a simple list (which is what you want 99% of the time),
  so the iterator value 'it' can end up on different iterations
  as multiple items, a single item, or no items.

  If you want to make the filter part fancy, you can obviously
  factor with map{} too, just like in the GROOVY-3526 examples:

    //-------------------------------------------------------
    def filt = {it%2}   // some arbitrarily complex filter
    def bar = [1,2,3].map{ filt(it) ? (it*=5) : [it*500,"hi"]}
    assert bar == [5,1000,"hi",15]
    //-------------------------------------------------------
 
    or even:

    //-------------------------------------------------------
    def filt  = {it%2}  
    def xform = { filt(it) ? (it*=5) : [it*500,"hi"]}
    def bar = [1,2,3].map(xform)
    assert bar == [5,1000,"hi",15]
    //-------------------------------------------------------

    ... or variations on the theme using currying.

  So, it looks like if you overloaded map{} with a two arg version
  that takes separate condition & transform closures then you'd
  have GROOVY-3526 + plus the ability to augment the list, if
  you really wanted that.  To my thinking, the 1-arg map{} idiom
  looks like a more straightforward variant of collect{} that
  has tried & true counterparts in other major languages,
  which is itself a valuable bonus.

  Maybe the "cross-language creole" thing isn't a big deal for
  some folks, but I think many people (like me!) find it
  incredibly helpful.  My fingers still keep wanting to type
  map{} in groovy, particularly when flipping between projects.
  I wish it "just worked".  :)


                       Regards,
                      -Jon



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Groovy2 shorthand for: collect{}.flatten()

Russel Winder
In reply to this post by Jon Cox
On Tue, 2011-06-07 at 19:39 -0700, Jon Cox wrote:
[ . . . ]
>   It would be convenient if groovy had a built-in
>   auto-flattening version of collect too.

Ignoring the fact that all language other than Smalltalk call these
operations map and reduce instead of collect and inject, it is probably
worth noting that most of them also have flatmap as well as map.

--
Russel.
=============================================================================
Dr Russel Winder      t: +44 20 7585 2200   voip: sip:[hidden email]
41 Buckmaster Road    m: +44 7770 465 077   xmpp: [hidden email]
London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder

signature.asc (205 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Groovy2 shorthand for: collect{}.flatten()

Jon Cox

 Russel,

* Russel Winder ([hidden email]) [110607 23:41]:
> On Tue, 2011-06-07 at 19:39 -0700, Jon Cox wrote:
> [ . . . ]
> >   It would be convenient if groovy had a built-in
> >   auto-flattening version of collect too.
>
> Ignoring the fact that all language other than Smalltalk call these
> operations map and reduce instead of collect and inject, it is probably
> worth noting that most of them also have flatmap as well as map.



  Do you know off the top of your head what various popular
  languages call the flat and non-flat versions of these
  functions?  Even an incomplete list would be great.

  Anyway, map{} clearly has "short and sweet" appeal!


                Cheers,
                -Jon


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Groovy2 shorthand for: collect{}.flatten()

Russel Winder
On Wed, 2011-06-08 at 11:08 -0700, Jon Cox wrote:
[ . . . ]
>   Do you know off the top of your head what various popular
>   languages call the flat and non-flat versions of these
>   functions?  Even an incomplete list would be great.

If I remember correctly, Haskell and Scala both use map for the
non-flattening version and flatMap for the flattening version.

>   Anyway, map{} clearly has "short and sweet" appeal!

Groovy should not call map what everyone else calls flatMap.  Too much
confusion.

--
Russel.
=============================================================================
Dr Russel Winder      t: +44 20 7585 2200   voip: sip:[hidden email]
41 Buckmaster Road    m: +44 7770 465 077   xmpp: [hidden email]
London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder

signature.asc (205 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Groovy2 shorthand for: collect{}.flatten()

Guillaume Laforge-4
On Thu, Jun 9, 2011 at 10:48, Russel Winder <[hidden email]> wrote:
On Wed, 2011-06-08 at 11:08 -0700, Jon Cox wrote:
[ . . . ]
>   Do you know off the top of your head what various popular
>   languages call the flat and non-flat versions of these
>   functions?  Even an incomplete list would be great.

If I remember correctly, Haskell and Scala both use map for the
non-flattening version and flatMap for the flattening version.

>   Anyway, map{} clearly has "short and sweet" appeal!

Groovy should not call map what everyone else calls flatMap.  Too much
confusion.

Agreed.
Following a similar naming convention, if we add such a method, we could call it collectMap, I guess.

--
Guillaume Laforge
Groovy Project Manager
Head of Groovy Development at SpringSource
http://www.springsource.com/g2one
Reply | Threaded
Open this post in threaded view
|

Re: Groovy2 shorthand for: collect{}.flatten()

melix
I guess you meant "flatCollect".

Le 09/06/2011 10:54, Guillaume Laforge a écrit :
On Thu, Jun 9, 2011 at 10:48, Russel Winder <[hidden email]> wrote:
On Wed, 2011-06-08 at 11:08 -0700, Jon Cox wrote:
[ . . . ]
>   Do you know off the top of your head what various popular
>   languages call the flat and non-flat versions of these
>   functions?  Even an incomplete list would be great.

If I remember correctly, Haskell and Scala both use map for the
non-flattening version and flatMap for the flattening version.

>   Anyway, map{} clearly has "short and sweet" appeal!

Groovy should not call map what everyone else calls flatMap.  Too much
confusion.

Agreed.
Following a similar naming convention, if we add such a method, we could call it collectMap, I guess.

--
Guillaume Laforge
Groovy Project Manager
Head of Groovy Development at SpringSource
http://www.springsource.com/g2one

Reply | Threaded
Open this post in threaded view
|

Re: Groovy2 shorthand for: collect{}.flatten()

Guillaume Laforge-4
LOL, yes, of course :-)
I should go back to bed this morning :-O

On Thu, Jun 9, 2011 at 10:57, Cédric Champeau <[hidden email]> wrote:
I guess you meant "flatCollect".

Le 09/06/2011 10:54, Guillaume Laforge a écrit :
On Thu, Jun 9, 2011 at 10:48, Russel Winder <[hidden email]> wrote:
On Wed, 2011-06-08 at 11:08 -0700, Jon Cox wrote:
[ . . . ]
>   Do you know off the top of your head what various popular
>   languages call the flat and non-flat versions of these
>   functions?  Even an incomplete list would be great.

If I remember correctly, Haskell and Scala both use map for the
non-flattening version and flatMap for the flattening version.

>   Anyway, map{} clearly has "short and sweet" appeal!

Groovy should not call map what everyone else calls flatMap.  Too much
confusion.

Agreed.
Following a similar naming convention, if we add such a method, we could call it collectMap, I guess.

--
Guillaume Laforge
Groovy Project Manager
Head of Groovy Development at SpringSource
http://www.springsource.com/g2one




--
Guillaume Laforge
Groovy Project Manager
Head of Groovy Development at SpringSource
http://www.springsource.com/g2one
Reply | Threaded
Open this post in threaded view
|

Re: Groovy2 shorthand for: collect{}.flatten()

Jon Cox
In reply to this post by melix

* C?dric Champeau ([hidden email]) [110609 01:58]:

> I guess you meant "flatCollect".
>
> Le 09/06/2011 10:54, Guillaume Laforge a ?crit :
>> On Thu, Jun 9, 2011 at 10:48, Russel Winder <[hidden email]  
>> <mailto:[hidden email]>> wrote:
>>
>>     On Wed, 2011-06-08 at 11:08 -0700, Jon Cox wrote:
>>     [ . . . ]
>>     >   Do you know off the top of your head what various popular
>>     >   languages call the flat and non-flat versions of these
>>     >   functions?  Even an incomplete list would be great.
>>
>>     If I remember correctly, Haskell and Scala both use map for the
>>     non-flattening version and flatMap for the flattening version.
>>
>>     >   Anyway, map{} clearly has "short and sweet" appeal!
>>
>>     Groovy should not call map what everyone else calls flatMap.  Too much
>>     confusion.
>>
>>
>> Agreed.
>> Following a similar naming convention, if we add such a method, we  
>> could call it collectMap, I guess.


      Hmm...
      To me, this is a verboseJavaFunctionNamingAntipattern :

             [....].collect{.... }
             [....].flatCollect{ ... }
           
      particularly compared to:

             [....].map{...}
 

      Maybe the following observation gives us a way out:
     
            //--------------------------------------------------------
            // Groovy has fully recursive flattening
            //--------------------------------------------------------
            flatten()            


            //--------------------------------------------------------
            // Groovy also has fully recursive flattening
            // using a Closure.   OK, cool, I guess.
            //--------------------------------------------------------
            flatten(Closure c)  


            //--------------------------------------------------------
            // Groovy lacks a cheap and cheerful way of saying
            // limit the flatting op to a specified number of levels.
            //
            // Aside:  If someone passes a negative value for 'level'
            //         the sensible thing seems to be to treat that
            //         just like the no-arg version of flatten()
            //         (ie: full recursion).  
            //--------------------------------------------------------
            flatten(int level)                  // Missing feature!


        Assuming I'd like to be able to say:

          //-----------------------------------------------------
          // Flattening away the outer level of nesting
          // in a Groovy list should be super easy,
          // just like it is in Ruby!
          //-----------------------------------------------------

          assert [ [1,[2,3],4], [5,[6,7],8] ].flatten(1)  ==
                 [  1,[2,3],4,   5,[6,7],8  ]


      This seem to point the way to making the map{} shorthand
      for collect+flatten even better.  Here are two possible
      variations on the theme:

      Possible form #1:

          [....].map {....}     // .collect{}.flatten()
          [....].map {....},0   // .collect{}
          [....].map {....},1   // .collect{}.flatten(1)

      Possible form #2:

          [....].map   {....}   // .collect{}.flatten()
          [....].map 0,{....}   // .collect{}
          [....].map 1,{....}   // .collect{}.flatten(1)

      The first form ( [...].map{...},n  ) seems better
      to me in terms of the logical flow of the line in
      my head; the second form ( [...].map n,{...} )
      highlights better the flattening level when the
      closure def is long.

      Does either of these ideas seem appealing?
      If so, which form would most people be likely to favor?


                        -Jon



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


1234 ... 8