-
Notifications
You must be signed in to change notification settings - Fork 6
/
take.go
155 lines (142 loc) · 4.85 KB
/
take.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package go2linq
import (
"github.com/solsw/errorhelper"
)
// Reimplementing LINQ to Objects: Part 23 - Take/Skip/TakeWhile/SkipWhile
// https://codeblog.jonskeet.uk/2011/01/02/reimplementing-linq-to-objects-part-23-take-skip-takewhile-skipwhile/
// https://learn.microsoft.com/dotnet/api/system.linq.enumerable.take
// https://learn.microsoft.com/dotnet/api/system.linq.enumerable.takelast
// https://learn.microsoft.com/dotnet/api/system.linq.enumerable.takewhile
func factoryTake[Source any](source Enumerable[Source], count int) func() Enumerator[Source] {
return func() Enumerator[Source] {
enr := source.GetEnumerator()
i := 0
return enrFunc[Source]{
mvNxt: func() bool {
if i < count && enr.MoveNext() {
i++
return true
}
return false
},
crrnt: func() Source { return enr.Current() },
rst: func() { i = 0; enr.Reset() },
}
}
}
// [Take] returns a specified number of contiguous elements from the start of a sequence.
//
// [Take]: https://learn.microsoft.com/dotnet/api/system.linq.enumerable.take
func Take[Source any](source Enumerable[Source], count int) (Enumerable[Source], error) {
if source == nil {
return nil, errorhelper.CallerError(ErrNilSource)
}
if count <= 0 {
return Empty[Source](), nil
}
return OnFactory(factoryTake(source, count)), nil
}
// TakeMust is like [Take] but panics in case of error.
func TakeMust[Source any](source Enumerable[Source], count int) Enumerable[Source] {
return errorhelper.Must(Take(source, count))
}
// [TakeLast] returns a new [Enumerable] that contains the last 'count' elements from 'source'.
//
// [TakeLast]: https://learn.microsoft.com/dotnet/api/system.linq.enumerable.takelast
func TakeLast[Source any](source Enumerable[Source], count int) (Enumerable[Source], error) {
if source == nil {
return nil, errorhelper.CallerError(ErrNilSource)
}
if count <= 0 {
return Empty[Source](), nil
}
sl := ToSliceMust(source)
return NewEnSlice(sl[len(sl)-count:]...), nil
}
// TakeLastMust is like [TakeLast] but panics in case of error.
func TakeLastMust[Source any](source Enumerable[Source], count int) Enumerable[Source] {
return errorhelper.Must(TakeLast(source, count))
}
func factoryTakeWhile[Source any](source Enumerable[Source], predicate func(Source) bool) func() Enumerator[Source] {
return func() Enumerator[Source] {
enr := source.GetEnumerator()
enough := false
var c Source
return enrFunc[Source]{
mvNxt: func() bool {
if enough {
return false
}
if enr.MoveNext() {
c = enr.Current()
if predicate(c) {
return true
}
}
enough = true
return false
},
crrnt: func() Source { return c },
rst: func() { enough = false; enr.Reset() },
}
}
}
// [TakeWhile] returns elements from a sequence as long as a specified condition is true.
//
// [TakeWhile]: https://learn.microsoft.com/dotnet/api/system.linq.enumerable.takewhile
func TakeWhile[Source any](source Enumerable[Source], predicate func(Source) bool) (Enumerable[Source], error) {
if source == nil {
return nil, errorhelper.CallerError(ErrNilSource)
}
if predicate == nil {
return nil, errorhelper.CallerError(ErrNilPredicate)
}
return OnFactory(factoryTakeWhile(source, predicate)), nil
}
// TakeWhileMust is like [TakeWhile] but panics in case of error.
func TakeWhileMust[Source any](source Enumerable[Source], predicate func(Source) bool) Enumerable[Source] {
return errorhelper.Must(TakeWhile(source, predicate))
}
func factoryTakeWhileIdx[Source any](source Enumerable[Source], predicate func(Source, int) bool) func() Enumerator[Source] {
return func() Enumerator[Source] {
enr := source.GetEnumerator()
enough := false
var c Source
i := -1 // position before the first element
return enrFunc[Source]{
mvNxt: func() bool {
if enough {
return false
}
if enr.MoveNext() {
c = enr.Current()
i++
if predicate(c, i) {
return true
}
}
enough = true
return false
},
crrnt: func() Source { return c },
rst: func() { enough = false; i = -1; enr.Reset() },
}
}
}
// [TakeWhileIdx] returns elements from a sequence as long as a specified condition is true.
// The element's index is used in the logic of the predicate function.
//
// [TakeWhileIdx]: https://learn.microsoft.com/dotnet/api/system.linq.enumerable.takewhile
func TakeWhileIdx[Source any](source Enumerable[Source], predicate func(Source, int) bool) (Enumerable[Source], error) {
if source == nil {
return nil, errorhelper.CallerError(ErrNilSource)
}
if predicate == nil {
return nil, errorhelper.CallerError(ErrNilPredicate)
}
return OnFactory(factoryTakeWhileIdx(source, predicate)), nil
}
// TakeWhileIdxMust is like [TakeWhileIdx] but panics in case of error.
func TakeWhileIdxMust[Source any](source Enumerable[Source], predicate func(Source, int) bool) Enumerable[Source] {
return errorhelper.Must(TakeWhileIdx(source, predicate))
}