...

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

Documentation: github.com/thoas/go-funk

     1  package funk
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  )
     7  
     8  type JoinFnc func(lx, rx reflect.Value) reflect.Value
     9  
    10  // Join combines two collections using the given join method.
    11  func Join(larr, rarr interface{}, fnc JoinFnc) interface{} {
    12  	if !IsCollection(larr) {
    13  		panic("First parameter must be a collection")
    14  	}
    15  	if !IsCollection(rarr) {
    16  		panic("Second parameter must be a collection")
    17  	}
    18  
    19  	lvalue := reflect.ValueOf(larr)
    20  	rvalue := reflect.ValueOf(rarr)
    21  	if NotEqual(lvalue.Type(), rvalue.Type()) {
    22  		panic("Parameters must have the same type")
    23  	}
    24  
    25  	return fnc(lvalue, rvalue).Interface()
    26  }
    27  
    28  // InnerJoin finds and returns matching data from two collections.
    29  func InnerJoin(lx, rx reflect.Value) reflect.Value {
    30  	result := reflect.MakeSlice(reflect.SliceOf(lx.Type().Elem()), 0, lx.Len()+rx.Len())
    31  	rhash := hashSlice(rx)
    32  	lhash := make(map[interface{}]struct{}, lx.Len())
    33  
    34  	for i := 0; i < lx.Len(); i++ {
    35  		v := lx.Index(i)
    36  		_, ok := rhash[v.Interface()]
    37  		_, alreadyExists := lhash[v.Interface()]
    38  		if ok && !alreadyExists {
    39  			lhash[v.Interface()] = struct{}{}
    40  			result = reflect.Append(result, v)
    41  		}
    42  	}
    43  	return result
    44  }
    45  
    46  // OuterJoin finds and returns dissimilar data from two collections.
    47  func OuterJoin(lx, rx reflect.Value) reflect.Value {
    48  	ljoin := LeftJoin(lx, rx)
    49  	rjoin := RightJoin(lx, rx)
    50  
    51  	result := reflect.MakeSlice(reflect.SliceOf(lx.Type().Elem()), ljoin.Len()+rjoin.Len(), ljoin.Len()+rjoin.Len())
    52  	for i := 0; i < ljoin.Len(); i++ {
    53  		result.Index(i).Set(ljoin.Index(i))
    54  	}
    55  	for i := 0; i < rjoin.Len(); i++ {
    56  		result.Index(ljoin.Len() + i).Set(rjoin.Index(i))
    57  	}
    58  
    59  	return result
    60  }
    61  
    62  // LeftJoin finds and returns dissimilar data from the first collection (left).
    63  func LeftJoin(lx, rx reflect.Value) reflect.Value {
    64  	result := reflect.MakeSlice(reflect.SliceOf(lx.Type().Elem()), 0, lx.Len())
    65  	rhash := hashSlice(rx)
    66  
    67  	for i := 0; i < lx.Len(); i++ {
    68  		v := lx.Index(i)
    69  		_, ok := rhash[v.Interface()]
    70  		if !ok {
    71  			result = reflect.Append(result, v)
    72  		}
    73  	}
    74  	return result
    75  }
    76  
    77  // LeftJoin finds and returns dissimilar data from the second collection (right).
    78  func RightJoin(lx, rx reflect.Value) reflect.Value { return LeftJoin(rx, lx) }
    79  
    80  func hashSlice(arr reflect.Value) map[interface{}]struct{} {
    81  	hash := map[interface{}]struct{}{}
    82  	for i := 0; i < arr.Len(); i++ {
    83  		v := arr.Index(i).Interface()
    84  		hash[v] = struct{}{}
    85  	}
    86  	return hash
    87  }
    88  
    89  // StringerJoin joins an array of elements which implement the `String() string` function.
    90  // Direct copy of strings.Join() with a few tweaks.
    91  func StringerJoin(elems []interface{ String() string }, sep string) string {
    92  	switch len(elems) {
    93  	case 0:
    94  		return ""
    95  	case 1:
    96  		return elems[0].String()
    97  	}
    98  	n := len(sep) * (len(elems) - 1)
    99  	for i := 0; i < len(elems); i++ {
   100  		n += len(elems[i].String())
   101  	}
   102  
   103  	var b strings.Builder
   104  	b.Grow(n)
   105  	b.WriteString(elems[0].String())
   106  	for _, s := range elems[1:] {
   107  		b.WriteString(sep)
   108  		b.WriteString(s.String())
   109  	}
   110  	return b.String()
   111  }
   112  

View as plain text