Created
July 24, 2019 14:12
-
-
Save kwilczynski/ca80d1bee25c95df170e097327511c23 to your computer and use it in GitHub Desktop.
Generic slice filter in Go.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"reflect" | |
"time" | |
) | |
func Filter(slice interface{}, filter interface{}) interface{} { | |
if slice == nil { | |
panic("first argument is not valid or nil pointer") | |
} | |
sliceKind := reflect.TypeOf(slice).Kind() | |
if sliceKind != reflect.Array && sliceKind != reflect.Slice { | |
panic("first argument is not a slice or array") | |
} | |
if filter == nil || reflect.TypeOf(filter).Kind() != reflect.Func { | |
panic("second argument is not a function or nil pointer") | |
} | |
filterValue := reflect.ValueOf(filter) | |
filterType := filterValue.Type() | |
filterArguments := filterType.NumIn() != 2 || filterType.NumOut() != 1 | |
if filterArguments || filterType.Out(0).Kind() != reflect.Bool { | |
panic("second argument signature is not valid") | |
} | |
sliceValue := reflect.ValueOf(slice) | |
sliceType := sliceValue.Type() | |
if !sliceType.Elem().ConvertibleTo(filterType.In(0)) { | |
panic("second argument signature does not match first argument type") | |
} | |
resultsType := reflect.SliceOf(sliceType.Elem()) | |
results := reflect.MakeSlice(resultsType, 0, 0) | |
for i := 0; i < sliceValue.Len(); i++ { | |
element := sliceValue.Index(i) | |
filterResult := filterValue.Call([]reflect.Value{element, reflect.ValueOf(i)})[0] | |
if filterResult.Interface().(bool) { | |
results = reflect.Append(results, element) | |
} | |
} | |
return results.Interface() | |
} | |
type Person struct { | |
Name string | |
DateOfBirth time.Time | |
} | |
func main() { | |
var t time.Time | |
var p []*Person | |
const dateFormat = `2006-01-02` | |
t, _ = time.Parse(dateFormat, `1879-03-14`) | |
p = append(p, &Person{"Albert Einstein", t}) | |
t, _ = time.Parse(dateFormat, `1856-07-10`) | |
p = append(p, &Person{"Nikola Tesla", t}) | |
t, _ = time.Parse(dateFormat, `1887-08-12`) | |
p = append(p, &Person{"Erwin Schrodinger", t}) | |
persons := Filter(p, func(p *Person, _ int) bool { | |
t, _ := time.Parse(dateFormat, `1880-01-01`) | |
return p.DateOfBirth.After(t) | |
}) | |
fmt.Printf("%T\n", persons) | |
for _, p := range persons.([]*Person) { | |
fmt.Printf("%+v\n", &Person{p.Name, p.DateOfBirth}) | |
} | |
strings := Filter([]string{"a", "b", "c"}, func(s string, _ int) bool { | |
return s > "a" | |
}) | |
fmt.Printf("%T\n", strings) | |
fmt.Println(strings) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment