Proposal Details
I propose the creation of two new function, Map
and Filter
, to the slices
package:
Map
Map
creates a new slice containing the results of running all indices of a slice through a provided functions
func Map[S ~[]E, E, R any](slice S, mapper func(int, E) R) []R
Example:
// Square all integers in a slice
slices.Map(
[]int{1, 2, 3, 4},
func(i, v int) int {
return v * v
},
)
// Output: [1 4 9 16]
Filter
Filter
create a new slice containing a subset of indices of an existing slice based on running all indices through a provided filter function
func Filter[S ~[]E, E any](slice S, filter func(int, E) bool) []E
Example:
// Filter out all odd numbers in a slice
slices.Filter(
[]int{1, 2, 3, 4},
func(i, v int) bool {
return v%2 == 0
},
)
// Output: [2 4]
Reasoning
Personally I find myself creating these exact function in most of my projects and they help a ton with writing clean code.
It allows me to change from code like this:
existingSlice := []int{1, 2, 3, 4}
filterSlice := make([]int, 0, len(existingSlice))
for _, v := range existingSlice {
if v%2 == 0 {
filterSlice = append(filterSlice, v)
}
}
mappedSlice := make([]string, len(filterSlice))
for i, v := range filterSlice {
mappedSlice[i] = strconv.Itoa(v)
}
and simplify it something like this:
existingSlice := []int{1, 2, 3, 4}
filterSlice := slice.Filter(existingSlice, func(i, v int) bool { return v%2 == 0 })
mappedSlice := slice.Map(filterSlice, func(i, v int) string { return strconv.Itoa(v) })
** Also note: this is super useful for doing inline operation
Implementation
New time contributor here, so I did not know that proposals were needed before making API change. I already have proposed implementation using the patterns that the slices
packages uses:
// Map returns a new slice containing the result of applying the mapper function to each element of the provided.
// The result has the same length as the input slice.
// The result is never nil.
// The result will be in the same order as the input slice.
// The mapper function must not modify the elements of the input slice.
func Map[S ~[]E, E, R any](slice S, mapper func(int, E) R) []R {
mappedSlice := make([]R, len(slice))
for i, v := range slice {
mappedSlice[i] = mapper(i, v)
}
return mappedSlice
}
// Filter returns a new slice containing only the elements of the provided slice for which the filter function returns true.
// The result has length <= len(slice).
// The result is never nil.
// The result will be in the same order as the input slice.
// The filter function must not modify the elements of the input slice.
func Filter[S ~[]E, E any](slice S, filter func(int, E) bool) []E {
filteredSlice := make([]E, 0, len(slice))
for i, v := range slice {
if filter(i, v) {
filteredSlice = append(filteredSlice, v)
}
}
return Clip(filteredSlice)
}
Comment From: gabyhelp
Similar Issues
- proposal: affected/package: slices #61252
- proposal: slices: add transform #67118
- higher-order functions built in to slice #14173
- proposal: slices: add Map function #61191
- proposal: slices: convert one slice to another #64742
- Proposal: add generic Filter to slices package #58014
- proposal: Go 2: Higher Order Collection Functions #31513
- slices: add `Map` #66333
- proposal: slices: add Trim, TrimRight, and TrimLeft #66672
- proposal: slices: partition slice into two slice by predicate #67326
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: 1nv8rzim
Reading through the similar issues, all of the similar proposals have been closed and they seem to point to https://github.com/golang/go/discussions/47203#discussioncomment-1034432 as the reason to why.
- Deleted Map, Filter, Reduce (probably better as part of a more comprehensive streams API somewhere else)
Reasoning to why these haven't been implemented is in anticipation of this "streams API" which I would assume would refer to the iter
package: https://github.com/golang/go/issues/61899. Likewise, slices
seems to be getting these iterator functions as recent as a month ago: https://go-review.googlesource.com/c/go/+/568477.
However, it seems as though functions like Map
and Filter
might have fallen through the cracks?
Comment From: ianlancetaylor
This is #61898. Thanks.