Re: [go-nuts] Go equivalent to Ruby collection.map { }?

674 views
Skip to first unread message

Patrick Mylund Nielsen

unread,
Feb 8, 2013, 9:05:50 AM2/8/13
to Michael Teter, golang-nuts
parts := strings.Split(string(line), "\t")
for i, v := range parts {
parts[i] = strings.TrimSpace(v)
}



On Fri, Feb 8, 2013 at 2:39 PM, Michael Teter <michae...@gmail.com> wrote:
Hello.  I'm completely new to Go, and I'm coming (most recently) from a Ruby background.

Since I don't know the Go names for things yet, I am having difficulty finding the answer to this question:

What is the Go equivalent to this Ruby line: my_collection.map { |item| some_function(item) }

Specifically, I am processing a large file line by line.  I split the line on tabs, and I want to TrimSpace() each element.  I am thinking something like this mixture of Go and Ruby:
parts := strings.Split(string(line), "\t").map { |s| strings.TrimSpace(s) }

Suggestions on how to ask this question to Google to find what I need?

Thanks in advance!

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Matt Kane's Brain

unread,
Feb 8, 2013, 9:27:02 AM2/8/13
to Patrick Mylund Nielsen, Michael Teter, golang-nuts
On Fri, Feb 8, 2013 at 9:05 AM, Patrick Mylund Nielsen
<pat...@patrickmylund.com> wrote:
> parts := strings.Split(string(line), "\t")
> for i, v := range parts {
> parts[i] = strings.TrimSpace(v)
> }

strings.Fields does just what you want in this specific case:

parts := strings.Fields(string(line))

It looks like there was an arrays.go package that offered something
akin to Python's list comprehensions or Ruby and Perl's map functions
for arrays in general, but that was in the pre-Go1 days and the
package appears to have been taken down. (described here
https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/-X581J-x8z4)

--
matt kane's brain
twitter: the_real_mkb / nynexrepublic
http://hydrogenproject.com

Daniel Bryan

unread,
Feb 8, 2013, 9:10:56 PM2/8/13
to golan...@googlegroups.com
there are two questions here:

* how to transform the data the way you want
* how to do it idiomatically in go

Patrick's answer is correct, but it's worth going a bit more deeply into the real difference: go does have anonymous inline functions - which is basically what Ruby's blocks are -  but since it's a strongly typed language, function composition will never look as clean as it does in Ruby.

Your ruby code is functionally equivalent to this Go code:

    func map(f func(s string) string, coll []string) []string {

        var newColl = make([]string, len(coll)

        for i, s := coll {

            newColl[i] = f(s)

        }

    }

    map(strings.TrimSpace, strings.Split(string(line, "\t)))

But that's generally not idiomatic in go: since the map() function must be typed, it's usually more concise just to do everything inline like Patrick showed. In programs where you're doing a lot of transformations between the same two types it can be worthwhile to write a mapper, but in practise most go code will look more or less like C for operations like this.

Sean Russell

unread,
Feb 9, 2013, 8:56:03 PM2/9/13
to golan...@googlegroups.com, Michael Teter
On Friday, February 8, 2013 9:05:50 AM UTC-5, Patrick Mylund Nielsen wrote:
parts := strings.Split(string(line), "\t")
for i, v := range parts {
parts[i] = strings.TrimSpace(v)
}

Not quite: map() doesn't change the original array contents, and this code does.  This code is map!().

--- SER

Patrick Mylund Nielsen

unread,
Feb 9, 2013, 9:58:36 PM2/9/13
to Sean Russell, golang-nuts, Michael Teter
Yes, equivalent, not identical. You probably don't want to allocate two arrays and just throw one away. If you do, it's:

parts := strings.Split(string(line), "\t")
nparts := make([]string, len(parts))
for i, v := range parts {
nparts[i] = strings.TrimSpace(v)
}


--

Sean Russell

unread,
Feb 10, 2013, 9:07:03 AM2/10/13
to golan...@googlegroups.com, Sean Russell, Michael Teter
On Saturday, February 9, 2013 9:58:36 PM UTC-5, Patrick Mylund Nielsen wrote:
Yes, equivalent, not identical. You probably don't want to allocate two arrays and just throw one away. If you do, it's:

parts := strings.Split(string(line), "\t")
nparts := make([]string, len(parts))
for i, v := range parts {
nparts[i] = strings.TrimSpace(v)
}

Yes.  I wasn't being critical; I was just pointing out that, in Ruby, there are two map() methods.  One which modifies in place (map!()) and one that doesn't (map()).  OP used the non-self-modifying version; I don't know why.  Maybe for concurrency, maybe because he wanted to preserve the original data for other operations... there are dozens of cases where you don't want to overwrite your original data, and it's an important distinction.

I admit it was pedantry, but justified pedantry, I think.

Cheers,

--- SER

Michael Teter

unread,
Feb 10, 2013, 5:27:48 PM2/10/13
to golan...@googlegroups.com, Sean Russell, Michael Teter
Thanks all for the educational responses.  I will obviously have to learn to live with a bit less brevity of code with Go compared to with Ruby, but that's a fair trade given the other benefits (time performance being my biggest need).

Regarding the map vs map!, I almost always use the functions that create new collections.  Now that I think about it, I don't have a lot of reasons for that choice :).  It it more functional to return a new data structure, but I'm not doing parallel programming in Ruby.  (I will, however, once I am more familiar with Go since I'm coming to Go to help me process very large datasets quickly.)

Michael
Reply all
Reply to author
Forward
0 new messages