...

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

Documentation: github.com/thoas/go-funk

     1  package funk
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  )
     7  
     8  // ForEach iterates over elements of collection and invokes iteratee
     9  // for each element.
    10  func ForEach(arr interface{}, predicate interface{}) {
    11  	if !IsIteratee(arr) {
    12  		panic("First parameter must be an iteratee")
    13  	}
    14  
    15  	var (
    16  		funcValue = reflect.ValueOf(predicate)
    17  		arrValue  = reflect.ValueOf(arr)
    18  		arrType   = arrValue.Type()
    19  		funcType  = funcValue.Type()
    20  	)
    21  
    22  	if arrType.Kind() == reflect.Slice || arrType.Kind() == reflect.Array {
    23  		if !IsFunction(predicate, 1, 0) {
    24  			panic("Second argument must be a function with one parameter")
    25  		}
    26  
    27  		arrElemType := arrValue.Type().Elem()
    28  
    29  		// Checking whether element type is convertible to function's first argument's type.
    30  		if !arrElemType.ConvertibleTo(funcType.In(0)) {
    31  			panic("Map function's argument is not compatible with type of array.")
    32  		}
    33  
    34  		for i := 0; i < arrValue.Len(); i++ {
    35  			funcValue.Call([]reflect.Value{arrValue.Index(i)})
    36  		}
    37  	}
    38  
    39  	if arrType.Kind() == reflect.Map {
    40  		if !IsFunction(predicate, 2, 0) {
    41  			panic("Second argument must be a function with two parameters")
    42  		}
    43  
    44  		// Type checking for Map<key, value> = (key, value)
    45  		keyType := arrType.Key()
    46  		valueType := arrType.Elem()
    47  
    48  		if !keyType.ConvertibleTo(funcType.In(0)) {
    49  			panic(fmt.Sprintf("function first argument is not compatible with %s", keyType.String()))
    50  		}
    51  
    52  		if !valueType.ConvertibleTo(funcType.In(1)) {
    53  			panic(fmt.Sprintf("function second argument is not compatible with %s", valueType.String()))
    54  		}
    55  
    56  		for _, key := range arrValue.MapKeys() {
    57  			funcValue.Call([]reflect.Value{key, arrValue.MapIndex(key)})
    58  		}
    59  	}
    60  }
    61  
    62  // ForEachRight iterates over elements of collection from the right and invokes iteratee
    63  // for each element.
    64  func ForEachRight(arr interface{}, predicate interface{}) {
    65  	if !IsIteratee(arr) {
    66  		panic("First parameter must be an iteratee")
    67  	}
    68  
    69  	var (
    70  		funcValue = reflect.ValueOf(predicate)
    71  		arrValue  = reflect.ValueOf(arr)
    72  		arrType   = arrValue.Type()
    73  		funcType  = funcValue.Type()
    74  	)
    75  
    76  	if arrType.Kind() == reflect.Slice || arrType.Kind() == reflect.Array {
    77  		if !IsFunction(predicate, 1, 0) {
    78  			panic("Second argument must be a function with one parameter")
    79  		}
    80  
    81  		arrElemType := arrValue.Type().Elem()
    82  
    83  		// Checking whether element type is convertible to function's first argument's type.
    84  		if !arrElemType.ConvertibleTo(funcType.In(0)) {
    85  			panic("Map function's argument is not compatible with type of array.")
    86  		}
    87  
    88  		for i := arrValue.Len() - 1; i >= 0; i-- {
    89  			funcValue.Call([]reflect.Value{arrValue.Index(i)})
    90  		}
    91  	}
    92  
    93  	if arrType.Kind() == reflect.Map {
    94  		if !IsFunction(predicate, 2, 0) {
    95  			panic("Second argument must be a function with two parameters")
    96  		}
    97  
    98  		// Type checking for Map<key, value> = (key, value)
    99  		keyType := arrType.Key()
   100  		valueType := arrType.Elem()
   101  
   102  		if !keyType.ConvertibleTo(funcType.In(0)) {
   103  			panic(fmt.Sprintf("function first argument is not compatible with %s", keyType.String()))
   104  		}
   105  
   106  		if !valueType.ConvertibleTo(funcType.In(1)) {
   107  			panic(fmt.Sprintf("function second argument is not compatible with %s", valueType.String()))
   108  		}
   109  
   110  		keys := Reverse(arrValue.MapKeys()).([]reflect.Value)
   111  
   112  		for _, key := range keys {
   113  			funcValue.Call([]reflect.Value{key, arrValue.MapIndex(key)})
   114  		}
   115  	}
   116  }
   117  
   118  // Head gets the first element of array.
   119  func Head(arr interface{}) interface{} {
   120  	value := redirectValue(reflect.ValueOf(arr))
   121  	valueType := value.Type()
   122  
   123  	kind := value.Kind()
   124  
   125  	if kind == reflect.Array || kind == reflect.Slice {
   126  		if value.Len() == 0 {
   127  			return nil
   128  		}
   129  
   130  		return value.Index(0).Interface()
   131  	}
   132  
   133  	panic(fmt.Sprintf("Type %s is not supported by Head", valueType.String()))
   134  }
   135  
   136  // Last gets the last element of array.
   137  func Last(arr interface{}) interface{} {
   138  	value := redirectValue(reflect.ValueOf(arr))
   139  	valueType := value.Type()
   140  
   141  	kind := value.Kind()
   142  
   143  	if kind == reflect.Array || kind == reflect.Slice {
   144  		if value.Len() == 0 {
   145  			return nil
   146  		}
   147  
   148  		return value.Index(value.Len() - 1).Interface()
   149  	}
   150  
   151  	panic(fmt.Sprintf("Type %s is not supported by Last", valueType.String()))
   152  }
   153  
   154  // Initial gets all but the last element of array.
   155  func Initial(arr interface{}) interface{} {
   156  	value := redirectValue(reflect.ValueOf(arr))
   157  	valueType := value.Type()
   158  
   159  	kind := value.Kind()
   160  
   161  	if kind == reflect.Array || kind == reflect.Slice {
   162  		length := value.Len()
   163  
   164  		if length <= 1 {
   165  			return arr
   166  		}
   167  
   168  		return value.Slice(0, length-1).Interface()
   169  	}
   170  
   171  	panic(fmt.Sprintf("Type %s is not supported by Initial", valueType.String()))
   172  }
   173  
   174  // Tail gets all but the first element of array.
   175  func Tail(arr interface{}) interface{} {
   176  	value := redirectValue(reflect.ValueOf(arr))
   177  	valueType := value.Type()
   178  
   179  	kind := value.Kind()
   180  
   181  	if kind == reflect.Array || kind == reflect.Slice {
   182  		length := value.Len()
   183  
   184  		if length <= 1 {
   185  			return arr
   186  		}
   187  
   188  		return value.Slice(1, length).Interface()
   189  	}
   190  
   191  	panic(fmt.Sprintf("Type %s is not supported by Initial", valueType.String()))
   192  }
   193  

View as plain text