filter and map functions

I am a JavaScript programmer beginning with Go. I tried to replicate filter and map functions like JavaScript's, as an exercise.

Here is what I came up with.

The filter function:

func Filter(slice interface{}, cb func(i interface{}) bool) []interface{}{
sliceValues := reflect.ValueOf(slice)
newSlice := []interface{}{}
for i := 0; i < sliceValues.Len(); i++{
v := sliceValues.Index(i).Interface()
passed := cb(v)
if passed{
newSlice = append(newSlice, v)
}
}
return newSlice
}


Usage:

a := []int {1,2,3}

result := Filter(a,func(i interface{}) bool{
v,_:= i.(int)
return v > 1
})

fmt.Println(result) // [2 3]


The map function:

func Map(slice interface{}, cb func(i interface{}) interface{}) []interface{}{
sliceValues := reflect.ValueOf(slice)
newSlice := []interface{}{}
for i := 0; i < sliceValues.Len(); i++{
v := sliceValues.Index(i).Interface()
modifiedValue := cb(v)
newSlice = append(newSlice, modifiedValue)
}
return newSlice


}

Usage:

a := []int {1,2,3}

result := Map(a,func(i interface{}) interface{}{
v,_:= i.(int)
return v + 1
})

fmt.Println(result) // [2 3 4]

• Why are you reinventing the wheel? – Mast Feb 18 at 17:37

From a mathematics and science genius:

"If I have seen further it is by standing on the shoulders of Giants." Isaac Newton

Wikipedia: Standing on the shoulders of giants

For Go giants, you might start with Rob Pike.

GitHub - robpike/filter: Simple apply/filter/reduce package.

I wanted to see how hard it was to implement this sort of thing in Go, with as nice an API as I could manage. It wasn't hard.

Having written it a couple of years ago, I haven't had occasion to use it once. Instead, I just use "for" loops.

You shouldn't use it either.

Take Rob Pike's advice and use "for" loops.

• OK, but my goal isn't just to make the functions. I need someone to point mistakes in my code so I can address them. – MrByte Feb 7 at 15:46

This answer is presuming your Filter and Map should take a slice given the first argument's name. There are other types that reflect's Len() works on which I'm ignoring for this answer. If you want to accept other types, I would suggest changing the name of the first argument to the functions to not be ‘slice’.

• Use gofmt (or derivative e.g. goimports) to consistently format your code. Your indentation is incorrect and there are spaces missing before open braces for blocks.
• Function parameter types should be restricted to the actual type expected by the function. Your functions take a parameter named slice but with type interface{}. Since this has to be a slice, you can restrict the type of the parameter to be []interface{}, requiring that a slice is passed in rather than anything.
• Using a slice as the function parameter type means you can iterate using range. You then don't need reflection for this job.
• You're using i for the for loop's iteration variable name, but also using i as the name of the argument to the callback which is actually the element not the index. Using two different parameter names (or removing the parameter name) would make it clearer that the callback is passed the element (v) not the index.
func Filter(slice []interface{}, cb func(interface{}) bool) []interface{} {
newSlice := []interface{}{}
for _, v := range slice {
if cb(v) {
newSlice = append(newSlice, v)
}
}
return newSlice
}