Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to map an array of objects in Go?

Coming from Node.js, I could do something like:

// given an array `list` of objects with a field `fruit`:

fruits = list.map(el => el.fruit) # which will return an array of fruit strings 

Any way to do that in an elegant one-liner in Go?

I know I can do it with a range loop, but I am looking for the possibility of a one-liner solution.

like image 305
Andrey Avatar asked Sep 05 '25 22:09

Andrey


1 Answers

Updated answer

Now that Go (1.23+) has standardised iterators, perhaps you'll find the following function useful:

func Map[T, U any](seq iter.Seq[T], f func(T) U) iter.Seq[U] {
    return func(yield func(U) bool) {
        for a := range seq {
            if !yield(f(a)) {
                return
            }
        }
    }
}

Example:

names := slices.Values([]string{"Alice", "Bob", "Carol"})
var total int
for n := range Map(names, utf8.RuneCountInString) {
    total += n
}
fmt.Println(total) // 13

(Playground)

Original answer

In Go, arrays used as function parameters are inflexible (because their length is encoded in their type) and costly (because a function operates on copies of its array arguments). I'm assuming you'd like to operate on slices rather than on arrays.

Because methods cannot take additional type arguments, you cannot simply declare a generic Map method in Go. However, you can define Map as a generic top-level function:

func Map[T, U any](ts []T, f func(T) U) []U {
    us := make([]U, len(ts))
    for i := range ts {
        us[i] = f(ts[i])
    }
    return us
}

Then you can write the following code,

names := []string{"Alice", "Bob", "Carol"}
fmt.Println(Map(names, utf8.RuneCountInString))

which prints [5 3 5] to stdout (try it out in this Playground).


Go 1.18 saw the addition of a golang.org/x/exp/slices package, which provides many convenient operations on slices, but a Map function is noticeably absent from it. The omission of that function was the result of a long discussion in the GitHub issue dedicated to the golang.org/x/exp/slices proposal; concerns included the following:

  • hidden cost (O(n)) of operations behind a one-liner
  • uncertainty about error handling inside Map
  • risk of encouraging a style that strays too far from Go's traditional style

Russ Cox ultimately elected to drop Map from the proposal because it's

probably better as part of a more comprehensive streams API somewhere else.

The slices package (added in Go 1.21) doesn't provide any Map function either.

like image 57
jub0bs Avatar answered Sep 09 '25 14:09

jub0bs