...

Source file src/github.com/thoas/go-funk/presence.go

Documentation: github.com/thoas/go-funk

     1  package funk
     2  
     3  import (
     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.
    11  func 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.
    53  func 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.
    60  func 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
   109  func 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
   134  func 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.
   160  func 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.
   190  func 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.
   200  func 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  

View as plain text