github.com/MontFerret/ferret@v0.18.0/pkg/stdlib/arrays/intersection.go (about)

     1  package arrays
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/MontFerret/ferret/pkg/runtime/core"
     7  	"github.com/MontFerret/ferret/pkg/runtime/values"
     8  	"github.com/MontFerret/ferret/pkg/runtime/values/types"
     9  )
    10  
    11  // INTERSECTION return the intersection of all arrays specified.
    12  // The result is an array of values that occur in all arguments.
    13  // The element order is random. Duplicates are removed.
    14  // @param {Any[], repeated} arrays - An arbitrary number of arrays as multiple arguments (at least 2).
    15  // @return {Any[]} - A single array with only the elements, which exist in all provided arrays.
    16  func Intersection(_ context.Context, args ...core.Value) (core.Value, error) {
    17  	return sections(args, len(args))
    18  }
    19  
    20  func sections(args []core.Value, count int) (core.Value, error) {
    21  	err := core.ValidateArgs(args, 2, core.MaxArgs)
    22  
    23  	if err != nil {
    24  		return values.None, err
    25  	}
    26  
    27  	intersections := make(map[uint64][]core.Value)
    28  	capacity := len(args)
    29  
    30  	for _, i := range args {
    31  		err := core.ValidateType(i, types.Array)
    32  
    33  		if err != nil {
    34  			return values.None, err
    35  		}
    36  
    37  		arr := i.(*values.Array)
    38  
    39  		arr.ForEach(func(value core.Value, idx int) bool {
    40  			h := value.Hash()
    41  
    42  			bucket, exists := intersections[h]
    43  
    44  			if !exists {
    45  				bucket = make([]core.Value, 0, 5)
    46  			}
    47  
    48  			bucket = append(bucket, value)
    49  			intersections[h] = bucket
    50  			bucketLen := len(bucket)
    51  
    52  			if bucketLen > capacity {
    53  				capacity = bucketLen
    54  			}
    55  
    56  			return true
    57  		})
    58  	}
    59  
    60  	result := values.NewArray(capacity)
    61  	required := count
    62  
    63  	for _, bucket := range intersections {
    64  		if len(bucket) == required {
    65  			result.Push(bucket[0])
    66  		}
    67  	}
    68  
    69  	return result, nil
    70  }