/
single.go
132 lines (122 loc) · 4.44 KB
/
single.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
package go2linq
import (
"github.com/solsw/generichelper"
)
// Reimplementing LINQ to Objects: Part 11 - First/Single/Last and the …OrDefault versions
// https://codeblog.jonskeet.uk/2010/12/29/reimplementing-linq-to-objects-part-11-first-single-last-and-the-ordefault-versions/
// https://learn.microsoft.com/dotnet/api/system.linq.enumerable.single
// https://learn.microsoft.com/dotnet/api/system.linq.enumerable.singleordefault
// [Single] returns the only element of a sequence and returns an error if there is not exactly one element in the sequence.
//
// [Single]: https://learn.microsoft.com/dotnet/api/system.linq.enumerable.single
func Single[Source any](source Enumerable[Source]) (Source, error) {
if source == nil {
return generichelper.ZeroValue[Source](), ErrNilSource
}
if counter, cok := source.(Counter); cok {
if counter.Count() == 0 {
return generichelper.ZeroValue[Source](), ErrEmptySource
}
if counter.Count() > 1 {
return generichelper.ZeroValue[Source](), ErrMultipleElements
}
if itemer, iok := source.(Itemer[Source]); iok {
return itemer.Item(0), nil
}
}
enr := source.GetEnumerator()
if !enr.MoveNext() {
return generichelper.ZeroValue[Source](), ErrEmptySource
}
if enr.MoveNext() {
return generichelper.ZeroValue[Source](), ErrMultipleElements
}
return enr.Current(), nil
}
// SingleMust is like [Single] but panics in case of error.
func SingleMust[Source any](source Enumerable[Source]) Source {
return generichelper.Must(Single(source))
}
// [SinglePred] returns the only element of a sequence that satisfies a specified condition.
//
// [SinglePred]: https://learn.microsoft.com/dotnet/api/system.linq.enumerable.single
func SinglePred[Source any](source Enumerable[Source], predicate func(Source) bool) (Source, error) {
if source == nil {
return generichelper.ZeroValue[Source](), ErrNilSource
}
if predicate == nil {
return generichelper.ZeroValue[Source](), ErrNilPredicate
}
enr := source.GetEnumerator()
empty := true
found := false
var r Source
for enr.MoveNext() {
empty = false
c := enr.Current()
if predicate(c) {
if found {
return generichelper.ZeroValue[Source](), ErrMultipleMatch
}
found = true
r = c
}
}
if empty {
return generichelper.ZeroValue[Source](), ErrEmptySource
}
if !found {
return generichelper.ZeroValue[Source](), ErrNoMatch
}
return r, nil
}
// SinglePredMust is like [SinglePred] but panics in case of error.
func SinglePredMust[Source any](source Enumerable[Source], predicate func(Source) bool) Source {
return generichelper.Must(SinglePred(source, predicate))
}
// [SingleOrDefault] returns the only element of a sequence or a [zero value] if the sequence is empty.
//
// [SingleOrDefault]: https://learn.microsoft.com/dotnet/api/system.linq.enumerable.singleordefault
// [zero value]: https://go.dev/ref/spec#The_zero_value
func SingleOrDefault[Source any](source Enumerable[Source]) (Source, error) {
if source == nil {
return generichelper.ZeroValue[Source](), ErrNilSource
}
r, err := Single(source)
if err != nil {
if err == ErrMultipleElements {
return generichelper.ZeroValue[Source](), ErrMultipleElements
}
return generichelper.ZeroValue[Source](), nil
}
return r, nil
}
// SingleOrDefaultMust is like [SingleOrDefault] but panics in case of error.
func SingleOrDefaultMust[Source any](source Enumerable[Source]) Source {
return generichelper.Must(SingleOrDefault(source))
}
// [SingleOrDefaultPred] returns the only element of a sequence that satisfies a specified condition
// or a [zero value] if no such element exists.
//
// [SingleOrDefaultPred]: https://learn.microsoft.com/dotnet/api/system.linq.enumerable.singleordefault
// [zero value]: https://go.dev/ref/spec#The_zero_value
func SingleOrDefaultPred[Source any](source Enumerable[Source], predicate func(Source) bool) (Source, error) {
if source == nil {
return generichelper.ZeroValue[Source](), ErrNilSource
}
if predicate == nil {
return generichelper.ZeroValue[Source](), ErrNilPredicate
}
r, err := SinglePred(source, predicate)
if err != nil {
if err == ErrMultipleMatch {
return generichelper.ZeroValue[Source](), ErrMultipleMatch
}
return generichelper.ZeroValue[Source](), nil
}
return r, nil
}
// SingleOrDefaultPredMust is like [SingleOrDefaultPred] but panics in case of error.
func SingleOrDefaultPredMust[Source any](source Enumerable[Source], predicate func(Source) bool) Source {
return generichelper.Must(SingleOrDefaultPred(source, predicate))
}