github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekaarr/slice.go (about)

     1  // Copyright © 2020-2022. All rights reserved.
     2  // Author: Ilya Stroy.
     3  // Contacts: iyuryevich@pm.me, https://github.com/qioalice
     4  // License: https://opensource.org/licenses/MIT
     5  
     6  package ekaarr
     7  
     8  import (
     9  	"sort"
    10  )
    11  
    12  func Sort[T any](in []T, cb func(a, b T) bool) []T {
    13  	sort.Slice(in, func(i, j int) bool { return cb(in[i], in[j]) })
    14  	return in
    15  }
    16  
    17  func Reduce[T any, R any](
    18  	in []T, out R, cb func(acc R, value T, index int, arr []T) R) R {
    19  
    20  	for i, n := 0, len(in); i < n; i++ {
    21  		out = cb(out, in[i], i, in)
    22  	}
    23  
    24  	return out
    25  }
    26  
    27  func Filter[T any](in []T, cb func(T) bool) []T {
    28  
    29  	// Copy on write.
    30  	// Meaning, there's no copy, if cb returns true for all elements.
    31  
    32  	var i, n, t = 0, len(in), true
    33  	for t = true; i < n && t; i++ {
    34  		t = cb(in[i])
    35  		// Don't forget i is incremented even when t set to false.
    36  	}
    37  
    38  	if !t {
    39  		i--
    40  	}
    41  	if i == n || i == n-1 {
    42  		return in[:i] // Nothing to filter.
    43  	}
    44  
    45  	// Maybe remained elements will be filtered all?
    46  	// If so, there's no need to make a copy so early.
    47  
    48  	var j = i
    49  	for t = true; i < n && t; i++ {
    50  		t = !cb(in[i])
    51  	}
    52  
    53  	if !t {
    54  		i--
    55  	}
    56  	if i == n {
    57  		return in[:j] // Leave only not filtered.
    58  	}
    59  
    60  	// Copy those which were not filtered.
    61  
    62  	var out = make([]T, 0, n) // <-- Make a copy.
    63  	for i := 0; i < j; i++ {
    64  		out = append(out, in[i])
    65  	}
    66  
    67  	for ; i < n; i++ {
    68  		if cb(in[i]) {
    69  			out = append(out, in[i])
    70  		}
    71  	}
    72  
    73  	return out
    74  }
    75  
    76  func Unique[T comparable](in []T) []T {
    77  	return unique(in, false)
    78  }
    79  
    80  func Distinct[T comparable](in []T) []T {
    81  	return unique(in, true)
    82  }
    83  
    84  func Remove[T comparable](in []T, remove ...T) []T {
    85  	return Filter(in, func(v T) bool { return !ContainsAny(remove, v) })
    86  }
    87  
    88  func ContainsAny[T comparable](in []T, search ...T) bool {
    89  	return contains(in, search, false)
    90  }
    91  
    92  func ContainsAll[T comparable](in []T, search ...T) bool {
    93  	return contains(in, search, true)
    94  }
    95  
    96  ////////////////////////////////////////////////////////////////////////////////
    97  ///// PRIVATE METHODS //////////////////////////////////////////////////////////
    98  ////////////////////////////////////////////////////////////////////////////////
    99  
   100  func contains[T comparable](in, search []T, allRequired bool) bool {
   101  
   102  	var found, stop bool
   103  
   104  	for i, n := 0, len(search); i < n && !stop; i++ {
   105  		found = false
   106  		for j, m := 0, len(in); j < m && !found; j++ {
   107  			found = search[i] == in[j]
   108  		}
   109  		stop = found != allRequired // DO NOT TRY TO SIMPLIFY THIS!!
   110  	}
   111  
   112  	return found
   113  }
   114  
   115  func unique[T comparable](in []T, includeOnce bool) []T {
   116  
   117  	var n = len(in)
   118  
   119  	for i := 0; i < n-1; i++ {
   120  		var duplicate = false
   121  
   122  		for j := i + 1; j < n; j++ {
   123  			if in[i] == in[j] {
   124  				in[j] = in[n-1]
   125  				n--
   126  				j--
   127  				duplicate = true
   128  			}
   129  		}
   130  
   131  		if !includeOnce && duplicate {
   132  			in[i] = in[n-1]
   133  			n--
   134  			i--
   135  		}
   136  	}
   137  
   138  	return in[:n]
   139  }