github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/tpl/collections/complement.go (about)

     1  // Copyright 2018 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package collections
    15  
    16  import (
    17  	"errors"
    18  	"fmt"
    19  	"reflect"
    20  )
    21  
    22  // Complement gives the elements in the last element of seqs that are not in
    23  // any of the others.
    24  // All elements of seqs must be slices or arrays of comparable types.
    25  //
    26  // The reasoning behind this rather clumsy API is so we can do this in the templates:
    27  //    {{ $c := .Pages | complement $last4 }}
    28  func (ns *Namespace) Complement(seqs ...interface{}) (interface{}, error) {
    29  	if len(seqs) < 2 {
    30  		return nil, errors.New("complement needs at least two arguments")
    31  	}
    32  
    33  	universe := seqs[len(seqs)-1]
    34  	as := seqs[:len(seqs)-1]
    35  
    36  	aset, err := collectIdentities(as...)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  
    41  	v := reflect.ValueOf(universe)
    42  	switch v.Kind() {
    43  	case reflect.Array, reflect.Slice:
    44  		sl := reflect.MakeSlice(v.Type(), 0, 0)
    45  		for i := 0; i < v.Len(); i++ {
    46  			ev, _ := indirectInterface(v.Index(i))
    47  			if _, found := aset[normalize(ev)]; !found {
    48  				sl = reflect.Append(sl, ev)
    49  			}
    50  		}
    51  		return sl.Interface(), nil
    52  	default:
    53  		return nil, fmt.Errorf("arguments to complement must be slices or arrays")
    54  	}
    55  }