1 package funk
2
3 import (
4 "fmt"
5 "math/rand"
6 "reflect"
7 "strings"
8 )
9
10
11
12
13 func Chunk(arr interface{}, size int) interface{} {
14 if !IsIteratee(arr) {
15 panic("First parameter must be neither array nor slice")
16 }
17
18 if size == 0 {
19 return arr
20 }
21
22 arrValue := reflect.ValueOf(arr)
23
24 arrType := arrValue.Type()
25
26 resultSliceType := reflect.SliceOf(arrType)
27
28
29 resultSlice := reflect.MakeSlice(resultSliceType, 0, 0)
30
31 itemType := arrType.Elem()
32
33 var itemSlice reflect.Value
34
35 itemSliceType := reflect.SliceOf(itemType)
36
37 length := arrValue.Len()
38
39 for i := 0; i < length; i++ {
40 if i%size == 0 || i == 0 {
41 if itemSlice.Kind() != reflect.Invalid {
42 resultSlice = reflect.Append(resultSlice, itemSlice)
43 }
44
45 itemSlice = reflect.MakeSlice(itemSliceType, 0, 0)
46 }
47
48 itemSlice = reflect.Append(itemSlice, arrValue.Index(i))
49
50 if i == length-1 {
51 resultSlice = reflect.Append(resultSlice, itemSlice)
52 }
53 }
54
55 return resultSlice.Interface()
56 }
57
58
59
60 func ToMap(in interface{}, pivot string) interface{} {
61 value := reflect.ValueOf(in)
62
63
64 if value.Kind() != reflect.Slice {
65 panic(fmt.Sprintf("%v must be a slice", in))
66 }
67
68 inType := value.Type()
69
70 structType := inType.Elem()
71
72
73 if structType.Kind() == reflect.Ptr {
74 structType = structType.Elem()
75 }
76
77 field, _ := structType.FieldByName(pivot)
78
79
80 collectionType := reflect.MapOf(field.Type, inType.Elem())
81
82
83 collection := reflect.MakeMap(collectionType)
84
85 for i := 0; i < value.Len(); i++ {
86 instance := value.Index(i)
87 var field reflect.Value
88
89 if instance.Kind() == reflect.Ptr {
90 field = instance.Elem().FieldByName(pivot)
91 } else {
92 field = instance.FieldByName(pivot)
93 }
94
95 collection.SetMapIndex(field, instance)
96 }
97
98 return collection.Interface()
99 }
100
101 func mapSlice(arrValue reflect.Value, funcValue reflect.Value) reflect.Value {
102 funcType := funcValue.Type()
103
104 if funcType.NumIn() != 1 || funcType.NumOut() == 0 || funcType.NumOut() > 2 {
105 panic("Map function with an array must have one parameter and must return one or two parameters")
106 }
107
108 arrElemType := arrValue.Type().Elem()
109
110
111 if !arrElemType.ConvertibleTo(funcType.In(0)) {
112 panic("Map function's argument is not compatible with type of array.")
113 }
114
115 if funcType.NumOut() == 1 {
116
117 resultSliceType := reflect.SliceOf(funcType.Out(0))
118
119
120 resultSlice := reflect.MakeSlice(resultSliceType, 0, 0)
121
122 for i := 0; i < arrValue.Len(); i++ {
123 result := funcValue.Call([]reflect.Value{arrValue.Index(i)})[0]
124
125 resultSlice = reflect.Append(resultSlice, result)
126 }
127
128 return resultSlice
129 }
130
131 if funcType.NumOut() == 2 {
132
133 collectionType := reflect.MapOf(funcType.Out(0), funcType.Out(1))
134
135
136 collection := reflect.MakeMap(collectionType)
137
138 for i := 0; i < arrValue.Len(); i++ {
139 results := funcValue.Call([]reflect.Value{arrValue.Index(i)})
140
141 collection.SetMapIndex(results[0], results[1])
142 }
143
144 return collection
145 }
146
147 return reflect.Value{}
148 }
149
150 func mapMap(arrValue reflect.Value, funcValue reflect.Value) reflect.Value {
151 funcType := funcValue.Type()
152
153 if funcType.NumIn() != 2 || funcType.NumOut() == 0 || funcType.NumOut() > 2 {
154 panic("Map function with a map must have two parameters and must return one or two parameters")
155 }
156
157
158 if funcType.NumOut() == 1 {
159
160 resultSliceType := reflect.SliceOf(funcType.Out(0))
161
162
163 resultSlice := reflect.MakeSlice(resultSliceType, 0, 0)
164
165 for _, key := range arrValue.MapKeys() {
166 results := funcValue.Call([]reflect.Value{key, arrValue.MapIndex(key)})
167
168 result := results[0]
169
170 resultSlice = reflect.Append(resultSlice, result)
171 }
172
173 return resultSlice
174 }
175
176
177 if funcType.NumOut() == 2 {
178
179 collectionType := reflect.MapOf(funcType.Out(0), funcType.Out(1))
180
181
182 collection := reflect.MakeMap(collectionType)
183
184 for _, key := range arrValue.MapKeys() {
185 results := funcValue.Call([]reflect.Value{key, arrValue.MapIndex(key)})
186
187 collection.SetMapIndex(results[0], results[1])
188
189 }
190
191 return collection
192 }
193
194 return reflect.Value{}
195 }
196
197
198 func Map(arr interface{}, mapFunc interface{}) interface{} {
199 result := mapFn(arr, mapFunc, "Map")
200
201 if result.IsValid() {
202 return result.Interface()
203 }
204
205 return nil
206 }
207
208 func mapFn(arr interface{}, mapFunc interface{}, funcName string) reflect.Value {
209 if !IsIteratee(arr) {
210 panic("First parameter must be an iteratee")
211 }
212
213 if !IsFunction(mapFunc) {
214 panic("Second argument must be function")
215 }
216
217 var (
218 funcValue = reflect.ValueOf(mapFunc)
219 arrValue = reflect.ValueOf(arr)
220 arrType = arrValue.Type()
221 )
222
223 kind := arrType.Kind()
224
225 if kind == reflect.Slice || kind == reflect.Array {
226 return mapSlice(arrValue, funcValue)
227 } else if kind == reflect.Map {
228 return mapMap(arrValue, funcValue)
229 }
230
231 panic(fmt.Sprintf("Type %s is not supported by "+funcName, arrType.String()))
232 }
233
234
235 func FlatMap(arr interface{}, mapFunc interface{}) interface{} {
236 result := mapFn(arr, mapFunc, "FlatMap")
237
238 if result.IsValid() {
239 return flatten(result).Interface()
240 }
241
242 return nil
243 }
244
245
246 func Flatten(out interface{}) interface{} {
247 return flatten(reflect.ValueOf(out)).Interface()
248 }
249
250 func flatten(value reflect.Value) reflect.Value {
251 sliceType := value.Type()
252
253 if (value.Kind() != reflect.Slice && value.Kind() != reflect.Array) ||
254 (sliceType.Elem().Kind() != reflect.Slice && sliceType.Elem().Kind() != reflect.Array) {
255 panic("Argument must be an array or slice of at least two dimensions")
256 }
257
258 resultSliceType := sliceType.Elem().Elem()
259
260 resultSlice := reflect.MakeSlice(reflect.SliceOf(resultSliceType), 0, 0)
261
262 length := value.Len()
263
264 for i := 0; i < length; i++ {
265 item := value.Index(i)
266
267 resultSlice = reflect.AppendSlice(resultSlice, item)
268 }
269
270 return resultSlice
271 }
272
273
274 func FlattenDeep(out interface{}) interface{} {
275 return flattenDeep(reflect.ValueOf(out)).Interface()
276 }
277
278 func flattenDeep(value reflect.Value) reflect.Value {
279 sliceType := sliceElem(value.Type())
280
281 resultSlice := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, 0)
282
283 return flattenRecursive(value, resultSlice)
284 }
285
286 func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
287 length := value.Len()
288
289 for i := 0; i < length; i++ {
290 item := value.Index(i)
291 kind := item.Kind()
292
293 if kind == reflect.Slice || kind == reflect.Array {
294 result = flattenRecursive(item, result)
295 } else {
296 result = reflect.Append(result, item)
297 }
298 }
299
300 return result
301 }
302
303
304 func Shuffle(in interface{}) interface{} {
305 value := reflect.ValueOf(in)
306 valueType := value.Type()
307
308 kind := value.Kind()
309
310 if kind == reflect.Array || kind == reflect.Slice {
311 length := value.Len()
312
313 resultSlice := makeSlice(value, length)
314
315 for i, v := range rand.Perm(length) {
316 resultSlice.Index(i).Set(value.Index(v))
317 }
318
319 return resultSlice.Interface()
320 }
321
322 panic(fmt.Sprintf("Type %s is not supported by Shuffle", valueType.String()))
323 }
324
325
326
327 func Reverse(in interface{}) interface{} {
328 value := reflect.ValueOf(in)
329 valueType := value.Type()
330
331 kind := value.Kind()
332
333 if kind == reflect.String {
334 return ReverseString(in.(string))
335 }
336
337 if kind == reflect.Array || kind == reflect.Slice {
338 length := value.Len()
339
340 resultSlice := makeSlice(value, length)
341
342 j := 0
343 for i := length - 1; i >= 0; i-- {
344 resultSlice.Index(j).Set(value.Index(i))
345 j++
346 }
347
348 return resultSlice.Interface()
349 }
350
351 panic(fmt.Sprintf("Type %s is not supported by Reverse", valueType.String()))
352 }
353
354
355 func Uniq(in interface{}) interface{} {
356 value := reflect.ValueOf(in)
357 valueType := value.Type()
358
359 kind := value.Kind()
360
361 if kind == reflect.Array || kind == reflect.Slice {
362 length := value.Len()
363
364 result := makeSlice(value, 0)
365
366 seen := make(map[interface{}]bool, length)
367 j := 0
368
369 for i := 0; i < length; i++ {
370 val := value.Index(i)
371 v := val.Interface()
372
373 if _, ok := seen[v]; ok {
374 continue
375 }
376
377 seen[v] = true
378 result = reflect.Append(result, val)
379 j++
380 }
381
382 return result.Interface()
383 }
384
385 panic(fmt.Sprintf("Type %s is not supported by Uniq", valueType.String()))
386 }
387
388
389
390 func ConvertSlice(in interface{}, out interface{}) {
391 srcValue := reflect.ValueOf(in)
392
393 dstValue := reflect.ValueOf(out)
394
395 if dstValue.Kind() != reflect.Ptr {
396 panic("Second argument must be a pointer")
397 }
398
399 dstValue = dstValue.Elem()
400
401 if srcValue.Kind() != reflect.Slice && srcValue.Kind() != reflect.Array {
402 panic("First argument must be an array or slice")
403 }
404
405 if dstValue.Kind() != reflect.Slice && dstValue.Kind() != reflect.Array {
406 panic("Second argument must be an array or slice")
407 }
408
409
410 direct := reflect.Indirect(dstValue)
411
412 length := srcValue.Len()
413
414 for i := 0; i < length; i++ {
415 dstValue = reflect.Append(dstValue, srcValue.Index(i))
416 }
417
418 direct.Set(dstValue)
419 }
420
421
422 func Drop(in interface{}, n int) interface{} {
423 value := reflect.ValueOf(in)
424 valueType := value.Type()
425
426 kind := value.Kind()
427
428 if kind == reflect.Array || kind == reflect.Slice {
429 length := value.Len()
430
431 resultSlice := makeSlice(value, length-n)
432
433 j := 0
434 for i := n; i < length; i++ {
435 resultSlice.Index(j).Set(value.Index(i))
436 j++
437 }
438
439 return resultSlice.Interface()
440
441 }
442
443 panic(fmt.Sprintf("Type %s is not supported by Drop", valueType.String()))
444 }
445
446
447
448
449 func Prune(in interface{}, paths []string) (interface{}, error) {
450 return pruneByTag(in, paths, nil )
451 }
452
453
454
455 func PruneByTag(in interface{}, paths []string, tag string) (interface{}, error) {
456 return pruneByTag(in, paths, &tag)
457 }
458
459
460
461
462 func pruneByTag(in interface{}, paths []string, tag *string) (interface{}, error) {
463
464 inValue := reflect.ValueOf(in)
465
466 ret := reflect.New(inValue.Type()).Elem()
467
468 for _, path := range paths {
469 parts := strings.Split(path, ".")
470 if err := prune(inValue, ret, parts, tag); err != nil {
471 return nil, err
472 }
473 }
474 return ret.Interface(), nil
475 }
476
477 func prune(inValue reflect.Value, ret reflect.Value, parts []string, tag *string) error {
478
479 if len(parts) == 0 {
480
481
482
483 ret.Set(inValue)
484 return nil
485 }
486
487 inKind := inValue.Kind()
488
489 switch inKind {
490 case reflect.Ptr:
491 if inValue.IsNil() {
492
493 return nil
494 }
495 if ret.IsNil() {
496
497 ret.Set(reflect.New(inValue.Type().Elem()))
498 }
499 return prune(inValue.Elem(), ret.Elem(), parts, tag)
500 case reflect.Struct:
501 part := parts[0]
502 var fValue reflect.Value
503 var fRet reflect.Value
504 if tag == nil {
505
506 fValue = inValue.FieldByName(part)
507 if !fValue.IsValid() {
508 return fmt.Errorf("field name %v is not found in struct %v", part, inValue.Type().String())
509 }
510 fRet = ret.FieldByName(part)
511 } else {
512
513 found := false
514 for i := 0; i < inValue.NumField(); i++ {
515 f := inValue.Type().Field(i)
516 if key, ok := f.Tag.Lookup(*tag); ok {
517 if key == part {
518 fValue = inValue.Field(i)
519 fRet = ret.Field(i)
520 found = true
521 break
522 }
523 }
524 }
525 if !found {
526 return fmt.Errorf("Struct tag %v is not found with key %v", *tag, part)
527 }
528 }
529
530 if fRet.IsZero() {
531 fRet.Set(reflect.New(fValue.Type()).Elem())
532 }
533 return prune(fValue, fRet, parts[1:], tag)
534 case reflect.Array, reflect.Slice:
535
536 length := inValue.Len()
537
538 if ret.IsZero() {
539 if inKind == reflect.Slice {
540 ret.Set(reflect.MakeSlice(inValue.Type(), length , length ))
541 } else {
542 ret.Set(reflect.New(inValue.Type()).Elem())
543 }
544 }
545 for j := 0; j < length; j++ {
546 if err := prune(inValue.Index(j), ret.Index(j), parts, tag); err != nil {
547 return err
548 }
549 }
550 default:
551 return fmt.Errorf("path %v cannot be looked up on kind of %v", strings.Join(parts, "."), inValue.Kind())
552 }
553
554 return nil
555 }
556
View as plain text