Home > Blockchain >  Can 'map' and 'reduce' be implemented in Go with generics
Can 'map' and 'reduce' be implemented in Go with generics

Time:06-16

I decided that now that generics have been introduced into Go that something like map/reduce should be possible. So, I took a naive stab at it and I get the error: ./prog.go:18:36: cannot use thing (variable of type int) as type I in argument to mapper

Which doesn't explain if the problem is fundamental or I am simply doing something wrong syntactically. Can generic map/reduce be implemented in Go?

package main

import "fmt"

func main() {
    things := []int{1, 2, 3, 4}
    results := Map(things, func(t int) int {
        return t   1
    })
    fmt.Printf("%v", results)
}

func Map[I interface{}, O interface{}](things []I, mapper func(thing I) O) []O {
    results := make([]O, 0, len(things))
    for thing := range things {
        results = append(results, mapper(thing))
    }
    return results
}

CodePudding user response:

You have incorrect use of range. A single variable extracted from range will be the index (type int), not the value (type I, which is only coincidentally int in this case).

Try

for _, thing := range things{...}

CodePudding user response:

This can be done quite easily. You have an error in your code, though right here:

for thing := range things {

You are iterating over the index values (int), not the values of type I. You're also specifying 2 constraints (types I and O) both set to be interface{}. You can just use any instead (it's shorthand for interface{})

So simply write:

func Map[T any, O any](things []T, mapper func(thing T) O) []O {
    result := make([]O, 0, len(things))
    for _, thing := range things {
        result = append(result, mapper(thing))
    }
    return result
}

Demo


This is quite closely related to some code I reviewed on codereview exchange here. After going through the code, and writing snippets with a ton of suggestions, I decided to just create a package and throw it up on github instead. You can find the repo here.

In it, there's some examples that may come in handy, or help you work through some other quirks WRT generics in golang. I wsa specifically thinking about this bit, where you can filter a generic map type using callbacks like so:

// given the sMap type
type sMap[K comparable, V any] struct {
    mu *sync.RWMutex
    m  map[K]V
}

// Filter returns a map containing the elements that matched the filter callback argument
func (s *sMap[K, V]) Filter(cb func(K, V) bool) map[K]V {
    s.mu.RLock()
    defer s.mu.RUnlock()
    ret := make(map[K]V, len(s.m))
    for k, v := range s.m {
        if cb(k, v) {
            ret[k] = v
        }
    }
    return ret
}
  • Related