1package funk 2 3import ( 4 "fmt" 5 "reflect" 6 "strings" 7) 8 9// Filter iterates over elements of collection, returning an array of 10// all elements predicate returns truthy for. 11func Filter(arr interface{}, predicate interface{}) interface{} { 12 if !IsIteratee(arr) { 13 panic("First parameter must be an iteratee") 14 } 15 16 if !IsFunction(predicate, 1, 1) { 17 panic("Second argument must be function") 18 } 19 20 funcValue := reflect.ValueOf(predicate) 21 22 funcType := funcValue.Type() 23 24 if funcType.Out(0).Kind() != reflect.Bool { 25 panic("Return argument should be a boolean") 26 } 27 28 arrValue := reflect.ValueOf(arr) 29 30 arrType := arrValue.Type() 31 32 // Get slice type corresponding to array type 33 resultSliceType := reflect.SliceOf(arrType.Elem()) 34 35 // MakeSlice takes a slice kind type, and makes a slice. 36 resultSlice := reflect.MakeSlice(resultSliceType, 0, 0) 37 38 for i := 0; i < arrValue.Len(); i++ { 39 elem := arrValue.Index(i) 40 41 result := funcValue.Call([]reflect.Value{elem})[0].Interface().(bool) 42 43 if result { 44 resultSlice = reflect.Append(resultSlice, elem) 45 } 46 } 47 48 return resultSlice.Interface() 49} 50 51// Find iterates over elements of collection, returning the first 52// element predicate returns truthy for. 53func Find(arr interface{}, predicate interface{}) interface{} { 54 _, val := FindKey(arr, predicate) 55 return val 56} 57 58// Find iterates over elements of collection, returning the first 59// element of an array and random of a map which predicate returns truthy for. 60func FindKey(arr interface{}, predicate interface{}) (matchKey, matchEle interface{}) { 61 if !IsIteratee(arr) { 62 panic("First parameter must be an iteratee") 63 } 64 65 if !IsFunction(predicate, 1, 1) { 66 panic("Second argument must be function") 67 } 68 69 funcValue := reflect.ValueOf(predicate) 70 71 funcType := funcValue.Type() 72 73 if funcType.Out(0).Kind() != reflect.Bool { 74 panic("Return argument should be a boolean") 75 } 76 77 arrValue := reflect.ValueOf(arr) 78 var keyArrs []reflect.Value 79 80 isMap := arrValue.Kind() == reflect.Map 81 if isMap { 82 keyArrs = arrValue.MapKeys() 83 } 84 for i := 0; i < arrValue.Len(); i++ { 85 var ( 86 elem reflect.Value 87 key reflect.Value 88 ) 89 if isMap { 90 key = keyArrs[i] 91 elem = arrValue.MapIndex(key) 92 } else { 93 key = reflect.ValueOf(i) 94 elem = arrValue.Index(i) 95 } 96 97 result := funcValue.Call([]reflect.Value{elem})[0].Interface().(bool) 98 99 if result { 100 return key.Interface(), elem.Interface() 101 } 102 } 103 104 return nil, nil 105} 106 107// IndexOf gets the index at which the first occurrence of value is found in array or return -1 108// if the value cannot be found 109func IndexOf(in interface{}, elem interface{}) int { 110 inValue := reflect.ValueOf(in) 111 112 elemValue := reflect.ValueOf(elem) 113 114 inType := inValue.Type() 115 116 if inType.Kind() == reflect.String { 117 return strings.Index(inValue.String(), elemValue.String()) 118 } 119 120 if inType.Kind() == reflect.Slice { 121 equalTo := equal(elem) 122 for i := 0; i < inValue.Len(); i++ { 123 if equalTo(reflect.Value{}, inValue.Index(i)) { 124 return i 125 } 126 } 127 } 128 129 return -1 130} 131 132// LastIndexOf gets the index at which the last occurrence of value is found in array or return -1 133// if the value cannot be found 134func LastIndexOf(in interface{}, elem interface{}) int { 135 inValue := reflect.ValueOf(in) 136 137 elemValue := reflect.ValueOf(elem) 138 139 inType := inValue.Type() 140 141 if inType.Kind() == reflect.String { 142 return strings.LastIndex(inValue.String(), elemValue.String()) 143 } 144 145 if inType.Kind() == reflect.Slice { 146 length := inValue.Len() 147 148 equalTo := equal(elem) 149 for i := length - 1; i >= 0; i-- { 150 if equalTo(reflect.Value{}, inValue.Index(i)) { 151 return i 152 } 153 } 154 } 155 156 return -1 157} 158 159// Contains returns true if an element is present in a iteratee. 160func Contains(in interface{}, elem interface{}) bool { 161 inValue := reflect.ValueOf(in) 162 elemValue := reflect.ValueOf(elem) 163 inType := inValue.Type() 164 165 switch inType.Kind() { 166 case reflect.String: 167 return strings.Contains(inValue.String(), elemValue.String()) 168 case reflect.Map: 169 equalTo := equal(elem, true) 170 for _, key := range inValue.MapKeys() { 171 if equalTo(key, inValue.MapIndex(key)) { 172 return true 173 } 174 } 175 case reflect.Slice, reflect.Array: 176 equalTo := equal(elem) 177 for i := 0; i < inValue.Len(); i++ { 178 if equalTo(reflect.Value{}, inValue.Index(i)) { 179 return true 180 } 181 } 182 default: 183 panic(fmt.Sprintf("Type %s is not supported by Contains, supported types are String, Map, Slice, Array", inType.String())) 184 } 185 186 return false 187} 188 189// Every returns true if every element is present in a iteratee. 190func Every(in interface{}, elements ...interface{}) bool { 191 for _, elem := range elements { 192 if !Contains(in, elem) { 193 return false 194 } 195 } 196 return true 197} 198 199// Some returns true if atleast one element is present in an iteratee. 200func Some(in interface{}, elements ...interface{}) bool { 201 for _, elem := range elements { 202 if Contains(in, elem) { 203 return true 204 } 205 } 206 return false 207} 208