gitee.com/mysnapcore/mysnapd@v0.1.0/strutil/intersection.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2021 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package strutil
    21  
    22  // Intersection computes the intersection of a set of slices, treating each
    23  // slice as a set. It does not mutate any of the input slices and returns a new
    24  // slice. It is recursive.
    25  func Intersection(slices ...[]string) []string {
    26  	// handle trivial cases
    27  	switch len(slices) {
    28  	case 0:
    29  		return nil
    30  	case 1:
    31  		return slices[0]
    32  	case 2:
    33  		// actually perform the intersection
    34  		l1 := slices[0]
    35  		l2 := slices[1]
    36  		guessLen := len(l1)
    37  		if len(l1) > len(l2) {
    38  			guessLen = len(l2)
    39  		}
    40  		alreadyAdded := map[string]bool{}
    41  		result := make([]string, 0, guessLen)
    42  		for _, item := range l1 {
    43  			if !alreadyAdded[item] && ListContains(l2, item) {
    44  				result = append(result, item)
    45  				alreadyAdded[item] = true
    46  			}
    47  		}
    48  		return result
    49  	}
    50  
    51  	// all other cases require some recursion operating on smaller chunks
    52  
    53  	// we take advantage of the fact that intersection is commutative and
    54  	// iteratively perform an intersection between a running intersection of
    55  	// all previous lists and the next list in the total set of slices
    56  
    57  	// TODO: this could be sped up with maps or any number of things, but
    58  	// hopefully this is only ever used on a few lists that are small in size
    59  	// so we can get away with this inefficient implementation
    60  	result := slices[0]
    61  	for _, s := range slices[1:] {
    62  		result = Intersection(result, s)
    63  	}
    64  	return result
    65  }