Skip to content

Instantly share code, notes, and snippets.

@flowonyx
Last active May 13, 2016 19:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save flowonyx/2ff7535deba492a8eee37c760c140ac2 to your computer and use it in GitHub Desktop.
Save flowonyx/2ff7535deba492a8eee37c760c140ac2 to your computer and use it in GitHub Desktop.
Filter a slice based on any field in the element using reflection
import (
"errors"
"reflect"
"github.com/fatih/structs"
)
// Filter takes a slice of structs that have a field with the given fieldName
// and uses that to filter based on value. The parameter, keep, determines
// whether the filter process keeps only the items filtered (true) or removes
// them (false).
func Filter(s interface{}, fieldName string, value interface{}, keep bool) error {
// ref is the pointer to the slice
ref := reflect.ValueOf(s)
// ensure that ref is a pointer to the slice
if ref.Kind() != reflect.Ptr || reflect.Indirect(ref).Kind() != reflect.Slice {
return errors.New("Filter must be called with a pointer to a slice")
}
// val is the slice
val := reflect.Indirect(ref)
// If the slice contains no items, no filtering is needed
if val.Len() == 0 {
return nil
}
// get the type of of item within the slice
typ := reflect.Indirect(ref).Type().Elem()
// check if this type has the field passed in
newElem := reflect.New(typ)
sin := structs.New(newElem.Interface())
// If it does not have the field, nothing to filter on
_, ok := sin.FieldOk(field)
if !ok {
return errors.New("field not found")
}
// Create a new slice to hold the filtered results
results := reflect.MakeSlice(reflect.Indirect(ref).Type(), 0, 0)
// loop through the array and check each item
for i := 0; i < val.Len(); i++ {
v := val.Index(i)
sval := structs.New(v.Interface())
b := sval.Field(field).Value() == value
if (keep && b) || (!keep && !b) {
results = reflect.Append(results, v)
}
}
// make the pointer go to the results slice
reflect.Indirect(ref).Set(results)
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment