55package collection
66
77import (
8+ "iter"
89 "slices"
910 "strings"
1011
1112 mapset "github.com/deckarep/golang-set/v2"
13+ "go.uber.org/atomic"
14+
15+ "github.com/ARM-software/golang-utils/utils/commonerrors"
16+ "github.com/ARM-software/golang-utils/utils/safecast"
1217)
1318
1419// Find looks for an element in a slice. If found it will
@@ -20,6 +25,22 @@ func Find(slice *[]string, val string) (int, bool) {
2025 return FindInSlice (true , * slice , val )
2126}
2227
28+ // FindInSequence searches a collection for an element satisfying the predicate.
29+ func FindInSequence [E any ](elements iter.Seq [E ], predicate Predicate [E ]) (int , bool ) {
30+ if elements == nil {
31+ return - 1 , false
32+ }
33+ idx := atomic .NewUint64 (0 )
34+ for e := range elements {
35+ if predicate (e ) {
36+ return safecast .ToInt (idx .Load ()), true
37+ }
38+ idx .Inc ()
39+ }
40+
41+ return - 1 , false
42+ }
43+
2344// FindInSlice finds if any values val are present in the slice and if so returns the first index.
2445// if strict, it checks for an exact match; otherwise it discards whitespaces and case.
2546func FindInSlice (strict bool , slice []string , val ... string ) (int , bool ) {
@@ -62,6 +83,46 @@ func UniqueEntries[T comparable](slice []T) []T {
6283 return subSet .ToSlice ()
6384}
6485
86+ // Unique returns all the unique values contained in a sequence.
87+ func Unique [T comparable ](s iter.Seq [T ]) []T {
88+ return UniqueEntries (slices .Collect (s ))
89+ }
90+
91+ // Union returns the union of two slices (only unique values are returned).
92+ func Union [T comparable ](slice1 , slice2 []T ) []T {
93+ subSet := mapset .NewSet [T ]()
94+ _ = subSet .Append (slice1 ... )
95+ _ = subSet .Append (slice2 ... )
96+ return subSet .ToSlice ()
97+ }
98+
99+ // Intersection returns the intersection of two slices (only unique values are returned).
100+ func Intersection [T comparable ](slice1 , slice2 []T ) []T {
101+ subSet1 := mapset .NewSet [T ]()
102+ subSet2 := mapset .NewSet [T ]()
103+ _ = subSet1 .Append (slice1 ... )
104+ _ = subSet2 .Append (slice2 ... )
105+ return subSet1 .Intersect (subSet2 ).ToSlice ()
106+ }
107+
108+ // Difference returns the Difference between slice1 and slice2 (only unique values are returned).
109+ func Difference [T comparable ](slice1 , slice2 []T ) []T {
110+ subSet1 := mapset .NewSet [T ]()
111+ subSet2 := mapset .NewSet [T ]()
112+ _ = subSet1 .Append (slice1 ... )
113+ _ = subSet2 .Append (slice2 ... )
114+ return subSet1 .Difference (subSet2 ).ToSlice ()
115+ }
116+
117+ // SymmetricDifference returns the symmetric difference between slice1 and slice2 (only unique values are returned).
118+ func SymmetricDifference [T comparable ](slice1 , slice2 []T ) []T {
119+ subSet1 := mapset .NewSet [T ]()
120+ subSet2 := mapset .NewSet [T ]()
121+ _ = subSet1 .Append (slice1 ... )
122+ _ = subSet2 .Append (slice2 ... )
123+ return subSet1 .SymmetricDifference (subSet2 ).ToSlice ()
124+ }
125+
65126// AnyFunc returns whether there is at least one element of slice s for which f() returns true.
66127func AnyFunc [S ~ []E , E any ](s S , f func (E ) bool ) bool {
67128 conditions := NewConditions (len (s ))
@@ -73,17 +134,50 @@ func AnyFunc[S ~[]E, E any](s S, f func(E) bool) bool {
73134
74135type FilterFunc [E any ] func (E ) bool
75136
137+ type Predicate [E any ] = FilterFunc [E ]
138+
76139// Filter returns a new slice that contains elements from the input slice which return true when they’re passed as a parameter to the provided filtering function f.
77- func Filter [S ~ []E , E any ](s S , f FilterFunc [E ]) (result S ) {
78- result = make (S , 0 , len (s ))
140+ func Filter [S ~ []E , E any ](s S , f FilterFunc [E ]) S {
141+ return slices.Collect [E ](FilterSequence [E ](slices .Values (s ), f ))
142+ }
79143
80- for i := range s {
81- if f (s [i ]) {
82- result = append (result , s [i ])
144+ // FilterSequence returns a new sequence that contains elements from the input sequence which return true when they’re passed as a parameter to the provided filtering function f.
145+ func FilterSequence [E any ](s iter.Seq [E ], f Predicate [E ]) (result iter.Seq [E ]) {
146+ return func (yield func (E ) bool ) {
147+ for v := range s {
148+ if f (v ) {
149+ if ! yield (v ) {
150+ return
151+ }
152+ }
83153 }
84154 }
155+ }
85156
86- return result
157+ // ForEachValues iterates over values and executes the passed function on each of them.
158+ func ForEachValues [E any ](f func (E ), values ... E ) {
159+ ForEach (values , f )
160+ }
161+
162+ // ForEach iterates over elements and executes the passed function on each element.
163+ func ForEach [S ~ []E , E any ](s S , f func (E )) {
164+ _ = Each [E ](slices .Values (s ), func (e E ) error {
165+ f (e )
166+ return nil
167+ })
168+ }
169+
170+ // Each iterates over a sequence and executes the passed function against each element.
171+ // If passed func returns an error, the iteration stops and the error is returned, unless it is EOF.
172+ func Each [T any ](s iter.Seq [T ], f func (T ) error ) error {
173+ for e := range s {
174+ err := f (e )
175+ if err != nil {
176+ err = commonerrors .Ignore (err , commonerrors .ErrEOF )
177+ return err
178+ }
179+ }
180+ return nil
87181}
88182
89183type MapFunc [T1 , T2 any ] func (T1 ) T2
@@ -95,15 +189,28 @@ func IdentityMapFunc[T any]() MapFunc[T, T] {
95189 }
96190}
97191
98- // Map creates a new slice and populates it with the results of calling the provided function on every element in input slice.
99- func Map [T1 any , T2 any ](s []T1 , f MapFunc [T1 , T2 ]) (result []T2 ) {
100- result = make ([]T2 , len (s ))
192+ // MapSequence creates a new sequences and populates it with the results of calling the provided function on every element of the input sequence.
193+ func MapSequence [T1 any , T2 any ](s iter.Seq [T1 ], f MapFunc [T1 , T2 ]) iter.Seq [T2 ] {
194+ return MapSequenceWithError [T1 , T2 ](s , func (t1 T1 ) (T2 , error ) {
195+ return f (t1 ), nil
196+ })
197+ }
101198
102- for i := range s {
103- result [i ] = f (s [i ])
199+ // MapSequenceWithError creates a new sequences and populates it with the results of calling the provided function on every element of the input sequence. If an error happens, the mapping stops.
200+ func MapSequenceWithError [T1 any , T2 any ](s iter.Seq [T1 ], f MapWithErrorFunc [T1 , T2 ]) iter.Seq [T2 ] {
201+ return func (yield func (T2 ) bool ) {
202+ for v := range s {
203+ mapped , subErr := f (v )
204+ if subErr != nil || ! yield (mapped ) {
205+ return
206+ }
207+ }
104208 }
209+ }
105210
106- return result
211+ // Map creates a new slice and populates it with the results of calling the provided function on every element in input slice.
212+ func Map [T1 any , T2 any ](s []T1 , f MapFunc [T1 , T2 ]) []T2 {
213+ return slices.Collect [T2 ](MapSequence [T1 , T2 ](slices .Values (s ), f ))
107214}
108215
109216// MapWithError creates a new slice and populates it with the results of calling the provided function on every element in input slice. If an error happens, the mapping stops and the error returned.
@@ -122,10 +229,32 @@ func MapWithError[T1 any, T2 any](s []T1, f MapWithErrorFunc[T1, T2]) (result []
122229 return
123230}
124231
232+ // OppositeFunc returns the opposite of a FilterFunc.
233+ func OppositeFunc [E any ](f FilterFunc [E ]) FilterFunc [E ] { return func (e E ) bool { return ! f (e ) } }
234+
125235// Reject is the opposite of Filter and returns the elements of collection for which the filtering function f returns false.
126236// This is functionally equivalent to slices.DeleteFunc but it returns a new slice.
127237func Reject [S ~ []E , E any ](s S , f FilterFunc [E ]) S {
128- return Filter (s , func (e E ) bool { return ! f (e ) })
238+ return Filter (s , OppositeFunc [E ](f ))
239+ }
240+
241+ // RejectSequence is the opposite of FilterSequence and returns the elements of collection for which the filtering function f returns false.
242+ func RejectSequence [E any ](s iter.Seq [E ], f FilterFunc [E ]) iter.Seq [E ] {
243+ return FilterSequence (s , OppositeFunc [E ](f ))
244+ }
245+
246+ // Reduce runs a reducer function f over all elements in the array, in ascending-index order, and accumulates them into a single value.
247+ func Reduce [T1 , T2 any ](s []T1 , accumulator T2 , f ReduceFunc [T1 , T2 ]) T2 {
248+ return ReducesSequence [T1 , T2 ](slices .Values (s ), accumulator , f )
249+ }
250+
251+ // ReducesSequence runs a reducer function f over all elements of a sequence, in ascending-index order, and accumulates them into a single value.
252+ func ReducesSequence [T1 , T2 any ](s iter.Seq [T1 ], accumulator T2 , f ReduceFunc [T1 , T2 ]) (result T2 ) {
253+ result = accumulator
254+ for e := range s {
255+ result = f (result , e )
256+ }
257+ return
129258}
130259
131260func match [E any ](e E , matches []FilterFunc [E ]) * Conditions {
@@ -148,13 +277,14 @@ func MatchAll[E any](e E, matches ...FilterFunc[E]) bool {
148277
149278type ReduceFunc [T1 , T2 any ] func (T2 , T1 ) T2
150279
151- // Reduce runs a reducer function f over all elements in the array, in ascending-index order, and accumulates them into a single value.
152- func Reduce [T1 , T2 any ](s []T1 , accumulator T2 , f ReduceFunc [T1 , T2 ]) (result T2 ) {
153- result = accumulator
154- for i := range s {
155- result = f (result , s [i ])
156- }
157- return
280+ // AllFunc returns whether f returns true for all the elements of slice s.
281+ func AllFunc [S ~ []E , E any ](s S , f func (E ) bool ) bool {
282+ return AllTrueSequence (slices .Values (s ), f )
283+ }
284+
285+ // AllTrueSequence returns whether f returns true for all the elements in a sequence.
286+ func AllTrueSequence [E any ](s iter.Seq [E ], f func (E ) bool ) bool {
287+ return AllSequence (MapSequence [E , bool ](s , f ))
158288}
159289
160290// AnyEmpty returns whether there is one entry in the slice which is empty.
@@ -164,15 +294,6 @@ func AnyEmpty(strict bool, slice []string) bool {
164294 return found
165295}
166296
167- // AllFunc returns whether f returns true for all the elements of slice s.
168- func AllFunc [S ~ []E , E any ](s S , f func (E ) bool ) bool {
169- conditions := NewConditions (len (s ))
170- for i := range s {
171- conditions .Add (f (s [i ]))
172- }
173- return conditions .All ()
174- }
175-
176297// AllNotEmpty returns whether all elements of the slice are not empty.
177298// If strict, then whitespaces are considered as empty strings
178299func AllNotEmpty (strict bool , slice []string ) bool {
0 commit comments