Skip to content

Commit f335e2d

Browse files
author
Roman Sorokin
committed
update project
1 parent 0f3840e commit f335e2d

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

pkg/glinq/operators.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,157 @@ func (s *stream[T]) Skip(n int) Stream[T] {
156156
},
157157
}
158158
}
159+
160+
// TakeOrderedBy takes the first n smallest elements from Stream using comparator function.
161+
// Uses a buffer of size n to keep track of the n smallest elements.
162+
// Stream is read lazily, and only the buffer is sorted before being returned.
163+
// This is a function (not a method) because in Go methods cannot have their own type parameters.
164+
//
165+
// Example:
166+
//
167+
// type Person struct { Age int; Name string }
168+
// people := []Person{{Age: 30, Name: "Alice"}, {Age: 25, Name: "Bob"}, {Age: 35, Name: "Charlie"}}
169+
// result := TakeOrderedBy(
170+
// From(people),
171+
// 2,
172+
// func(a, b Person) bool { return a.Age < b.Age },
173+
// ).ToSlice()
174+
// // []Person{{Age: 25, Name: "Bob"}, {Age: 30, Name: "Alice"}}
175+
func TakeOrderedBy[T any](s Stream[T], n int, less func(a, b T) bool) Stream[T] {
176+
if n <= 0 {
177+
return Empty[T]()
178+
}
179+
180+
var buf []T
181+
var result []T
182+
var materialized bool
183+
184+
return &stream[T]{
185+
source: func() (T, bool) {
186+
if !materialized {
187+
// Materialize stream and build buffer
188+
for {
189+
value, ok := s.Next()
190+
if !ok {
191+
break
192+
}
193+
194+
if len(buf) < n {
195+
buf = append(buf, value)
196+
} else {
197+
// Find maximum element in buffer (according to less)
198+
maxIdx := 0
199+
for i := 1; i < len(buf); i++ {
200+
if less(buf[maxIdx], buf[i]) {
201+
maxIdx = i
202+
}
203+
}
204+
// Replace if current value is smaller (according to less)
205+
if less(value, buf[maxIdx]) {
206+
buf[maxIdx] = value
207+
}
208+
}
209+
}
210+
211+
// Sort buffer in ascending order using less function
212+
result = make([]T, len(buf))
213+
copy(result, buf)
214+
for i := 0; i < len(result); i++ {
215+
for j := i + 1; j < len(result); j++ {
216+
if less(result[j], result[i]) {
217+
result[i], result[j] = result[j], result[i]
218+
}
219+
}
220+
}
221+
222+
materialized = true
223+
}
224+
225+
if len(result) == 0 {
226+
var zero T
227+
return zero, false
228+
}
229+
230+
value := result[0]
231+
result = result[1:]
232+
return value, true
233+
},
234+
}
235+
}
236+
237+
// TakeOrderedDescendingBy takes the first n largest elements from Stream using comparator function.
238+
// Uses a buffer of size n to keep track of the n largest elements.
239+
// Stream is read lazily, and only the buffer is sorted before being returned.
240+
// This is a function (not a method) because in Go methods cannot have their own type parameters.
241+
//
242+
// Example:
243+
//
244+
// type Person struct { Age int; Name string }
245+
// people := []Person{{Age: 30, Name: "Alice"}, {Age: 25, Name: "Bob"}, {Age: 35, Name: "Charlie"}}
246+
// result := TakeOrderedDescendingBy(
247+
// From(people),
248+
// 2,
249+
// func(a, b Person) bool { return a.Age < b.Age },
250+
// ).ToSlice()
251+
// // []Person{{Age: 35, Name: "Charlie"}, {Age: 30, Name: "Alice"}}
252+
func TakeOrderedDescendingBy[T any](s Stream[T], n int, less func(a, b T) bool) Stream[T] {
253+
if n <= 0 {
254+
return Empty[T]()
255+
}
256+
257+
var buf []T
258+
var result []T
259+
var materialized bool
260+
261+
return &stream[T]{
262+
source: func() (T, bool) {
263+
if !materialized {
264+
// Materialize stream and build buffer
265+
for {
266+
value, ok := s.Next()
267+
if !ok {
268+
break
269+
}
270+
271+
if len(buf) < n {
272+
buf = append(buf, value)
273+
} else {
274+
// Find minimum element in buffer (according to less)
275+
minIdx := 0
276+
for i := 1; i < len(buf); i++ {
277+
if less(buf[i], buf[minIdx]) {
278+
minIdx = i
279+
}
280+
}
281+
// Replace if current value is larger (according to less)
282+
if less(buf[minIdx], value) {
283+
buf[minIdx] = value
284+
}
285+
}
286+
}
287+
288+
// Sort buffer in descending order using less function
289+
result = make([]T, len(buf))
290+
copy(result, buf)
291+
for i := 0; i < len(result); i++ {
292+
for j := i + 1; j < len(result); j++ {
293+
if less(result[i], result[j]) {
294+
result[i], result[j] = result[j], result[i]
295+
}
296+
}
297+
}
298+
299+
materialized = true
300+
}
301+
302+
if len(result) == 0 {
303+
var zero T
304+
return zero, false
305+
}
306+
307+
value := result[0]
308+
result = result[1:]
309+
return value, true
310+
},
311+
}
312+
}

0 commit comments

Comments
 (0)