github.com/kazu/loncha@v0.6.3/intersect.go (about)

     1  //go:build go1.18
     2  // +build go1.18
     3  
     4  package loncha
     5  
     6  import "sort"
     7  
     8  type IntersectOpt struct {
     9  	Uniq bool
    10  }
    11  
    12  // Intersect ... intersection between 2 slice.
    13  func Intersect[T comparable](slice1, slice2 []T, opts ...Opt[IntersectOpt]) (result []T) {
    14  
    15  	param, fn := MergeOpts(opts...)
    16  	defer fn(param)
    17  
    18  	exists := map[T]bool{}
    19  	already := map[T]bool{}
    20  
    21  	for _, v := range slice1 {
    22  		exists[v] = true
    23  	}
    24  
    25  	result = make([]T, 0, len(exists))
    26  
    27  	for _, v := range slice2 {
    28  		if param.Param.Uniq && already[v] {
    29  			continue
    30  		}
    31  
    32  		if exists[v] {
    33  			result = append(result, v)
    34  			already[v] = true
    35  		}
    36  	}
    37  	return
    38  }
    39  
    40  // Ordered ... copy from https://github.com/golang/go/blob/go1.18.3/test/typeparam/ordered.go
    41  type Ordered interface {
    42  	~int | ~int8 | ~int16 | ~int32 | ~int64 |
    43  		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
    44  		~float32 | ~float64 |
    45  		~string
    46  }
    47  
    48  type IdentFunc[T any, V Ordered] func(slice []T, i int) V
    49  
    50  // IntersectSorted ... intersection between 2 sorted slice
    51  func IntersectSorted[T any, V Ordered](slice1, slice2 []T, IdentFn IdentFunc[T, V]) (result []T) {
    52  
    53  	jn := 0
    54  	for i, v := range slice1 {
    55  		key := IdentFn(slice1, i)
    56  		idx := sort.Search(len(slice2)-jn, func(j int) bool {
    57  			return IdentFn(slice2, j+jn) >= key
    58  		})
    59  		if idx < len(slice2) && IdentFn(slice2, idx) == key {
    60  			result = append(result, v)
    61  			jn = idx
    62  		}
    63  	}
    64  	return result
    65  }