-
Notifications
You must be signed in to change notification settings - Fork 0
/
filter.go
83 lines (63 loc) · 2 KB
/
filter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package functools
import (
"reflect"
"errors"
)
/*
'Filter' function construct a slice from those elements of iterable 'slice'
which can be represented as bool 'true'. Each element of the slice is converted to bool
by 'functools.ToBool' function. Function allowes slices and arrays.
Filter(slice) slice
FilterSafe(slice) (slice, err)
'FilterFunc' function construct a slice from those elements of iterable 'slice'
for which 'func' returns 'true'. Function allowes slices and arrays.
FilterFunc(func, slice) slice
FilterFuncSafe(func, slice) (slice, err)
*/
func filter(function, slice interface{}) interface{} {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array {
raise(errors.New("The passed collection is not a slice or an array"), "Filter")
}
fn := reflect.ValueOf(function)
t := rv.Type().Elem()
if !verifyFilterFuncType(fn, t) {
raise(errors.New("Function must be of type func(" + t.String() +
") bool or func(interface{}) bool"), "Filter")
}
var param [1]reflect.Value
out := reflect.MakeSlice(rv.Type(), 0, rv.Len())
for i := 0; i < rv.Len(); i++ {
param[0] = rv.Index(i)
if fn.Call(param[:])[0].Bool() {
out = reflect.Append(out, rv.Index(i))
}
}
return out.Interface()
}
func verifyFilterFuncType(fn reflect.Value, elType reflect.Type) bool {
if fn.Kind() != reflect.Func {
return false
}
if fn.Type().NumIn() != 1 || fn.Type().NumOut() != 1 {
return false
}
return ((fn.Type().In(0).Kind() == reflect.Interface || fn.Type().In(0) == elType) &&
fn.Type().Out(0).Kind() == reflect.Bool)
}
func Filter(slice interface{}) interface{} {
return filter(ToBool, slice)
}
func FilterSafe(slice interface{}) (result interface{}, err error) {
defer except(&err)
result = filter(ToBool, slice)
return
}
func FilterFunc(function, slice interface{}) interface{} {
return filter(function, slice)
}
func FilterFuncSafe(function, slice interface{}) (result interface{}, err error) {
defer except(&err)
result = filter(function, slice)
return
}