github.com/kazu/loncha@v0.6.3/select.go (about) 1 package loncha 2 3 import ( 4 "errors" 5 "reflect" 6 "sort" 7 ) 8 9 var ( 10 ERR_SLICE_TYPE error = errors.New("parameter must be slice or pointer of slice") 11 ERR_POINTER_SLICE_TYPE error = errors.New("parameter must be pointer of slice") 12 ERR_NOT_FOUND error = errors.New("data is not found") 13 ERR_ELEMENT_INVALID_TYPE error = errors.New("slice element is invalid type") 14 ERR_INVALID_INDEX error = errors.New("invalid index") 15 ) 16 17 type CondFunc func(idx int) bool 18 type CompareFunc func(i, j int) bool 19 20 func slice2Reflect(slice interface{}) (reflect.Value, error) { 21 rv := reflect.ValueOf(slice) 22 if rv.Kind() != reflect.Ptr { 23 return reflect.ValueOf(nil), ERR_SLICE_TYPE 24 } 25 26 if rv.Elem().Kind() != reflect.Slice { 27 return reflect.ValueOf(nil), ERR_SLICE_TYPE 28 } 29 return rv, nil 30 } 31 32 func sliceElm2Reflect(slice interface{}) (reflect.Value, error) { 33 rv := reflect.ValueOf(slice) 34 35 if rv.Kind() == reflect.Slice { 36 return rv, nil 37 } 38 39 if rv.Kind() != reflect.Ptr { 40 return reflect.ValueOf(nil), ERR_POINTER_SLICE_TYPE 41 } 42 43 if rv.Elem().Kind() != reflect.Slice { 44 return reflect.ValueOf(nil), ERR_SLICE_TYPE 45 } 46 return rv.Elem(), nil 47 } 48 49 // Reverse ... Transforms an array such that the first element will become the last, the second element will become the second to last, etc. 50 func Reverse(slice interface{}) { 51 52 sort.Slice(slice, func(i, j int) bool { return i > j }) 53 } 54 55 // Select ... return all element on match of CondFunc 56 func Select(slice interface{}, fn CondFunc) (interface{}, error) { 57 58 rv, err := sliceElm2Reflect(slice) 59 60 if err != nil { 61 return nil, err 62 } 63 newSlice := reflect.MakeSlice(rv.Type(), rv.Len(), rv.Cap()) 64 65 reflect.Copy(newSlice, rv) 66 67 ptr := reflect.New(newSlice.Type()) 68 ptr.Elem().Set(newSlice) 69 70 filter(ptr, fn) 71 72 return ptr.Elem().Interface(), nil 73 } 74 75 // OldFilter ... OldFilter element with mached funcs 76 // Deprecated: should use FIlter 77 func OldFilter(slice interface{}, funcs ...CondFunc) error { 78 79 rv, err := slice2Reflect(slice) 80 if err != nil { 81 return err 82 } 83 84 filter(rv, funcs...) 85 return nil 86 } 87 88 // Delete ... Delete element with mached funcs 89 func Delete(slice interface{}, funcs ...CondFunc) error { 90 rv, err := slice2Reflect(slice) 91 if err != nil { 92 return err 93 } 94 95 innterFilter(rv, false, funcs...) 96 return nil 97 } 98 99 func filter(pRv reflect.Value, funcs ...CondFunc) { 100 101 innterFilter(pRv, true, funcs...) 102 } 103 104 func innterFilter(pRv reflect.Value, keep bool, funcs ...CondFunc) { 105 106 rv := pRv.Elem() 107 108 length := rv.Len() 109 if length == 0 { 110 return 111 } 112 113 movelist := make([]int, length) 114 newIdx := 0 115 116 for i := 0; i < length; i++ { 117 allok := (true == keep) 118 for _, f := range funcs { 119 if !f(i) { 120 allok = (false == keep) 121 } 122 } 123 124 if allok { 125 movelist[i] = newIdx 126 newIdx++ 127 } else { 128 movelist[i] = -1 129 } 130 } 131 132 if newIdx == length { 133 return 134 } 135 136 swap := reflect.Swapper(pRv.Elem().Interface()) 137 138 for i, v := range movelist { 139 if v != -1 { 140 swap(i, v) 141 } 142 } 143 144 pRv.Elem().SetLen(newIdx) 145 146 }