@@ -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