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 }