patterngoCritical
Most idiomatic way to select elements from an array in Golang?
Viewed 0 times
idiomaticarrayfromselectgolangwaymostelements
Problem
I have an array of strings, and I'd like to exclude values that start in
I can loop through each element, run the
Just for example, the same thing might be done in Ruby as
foo_ OR are longer than 7 characters.I can loop through each element, run the
if statement, and add it to a slice along the way. But I was curious if there was an idiomatic or more golang-like way of accomplishing that.Just for example, the same thing might be done in Ruby as
my_array.select! { |val| val !~ /^foo_/ && val.length <= 7 }Solution
There is no one-liner as you have it in Ruby, but with a helper function you can make it almost as short.
Here's our helper function that loops over a slice, and selects and returns only the elements that meet a criterion captured by a function value:
Starting with Go 1.18, we can write it generic so it will work with all types, not just
Using this helper function your task:
Output (try it on the Go Playground, or the generic version: Go Playground):
Note:
If it is expected that many elements will be selected, it might be profitable to allocate a "big"
Note #2:
In my example I chose a
Here's our helper function that loops over a slice, and selects and returns only the elements that meet a criterion captured by a function value:
func filter(ss []string, test func(string) bool) (ret []string) {
for _, s := range ss {
if test(s) {
ret = append(ret, s)
}
}
return
}Starting with Go 1.18, we can write it generic so it will work with all types, not just
string:func filter[T any](ss []T, test func(T) bool) (ret []T) {
for _, s := range ss {
if test(s) {
ret = append(ret, s)
}
}
return
}Using this helper function your task:
ss := []string{"foo_1", "asdf", "loooooooong", "nfoo_1", "foo_2"}
mytest := func(s string) bool { return !strings.HasPrefix(s, "foo_") && len(s) <= 7 }
s2 := filter(ss, mytest)
fmt.Println(s2)Output (try it on the Go Playground, or the generic version: Go Playground):
[asdf nfoo_1]Note:
If it is expected that many elements will be selected, it might be profitable to allocate a "big"
ret slice beforehand, and use simple assignment instead of the append(). And before returning, slice the ret to have a length equal to the number of selected elements.Note #2:
In my example I chose a
test() function which tells if an element is to be returned. So I had to invert your "exclusion" condition. Obviously you may write the helper function to expect a tester function which tells what to exclude (and not what to include).Code Snippets
func filter(ss []string, test func(string) bool) (ret []string) {
for _, s := range ss {
if test(s) {
ret = append(ret, s)
}
}
return
}func filter[T any](ss []T, test func(T) bool) (ret []T) {
for _, s := range ss {
if test(s) {
ret = append(ret, s)
}
}
return
}ss := []string{"foo_1", "asdf", "loooooooong", "nfoo_1", "foo_2"}
mytest := func(s string) bool { return !strings.HasPrefix(s, "foo_") && len(s) <= 7 }
s2 := filter(ss, mytest)
fmt.Println(s2)[asdf nfoo_1]Context
Stack Overflow Q#37562873, score: 148
Revisions (0)
No revisions yet.