/
tomap.go
75 lines (69 loc) · 2.62 KB
/
tomap.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
package go2linq
import (
"github.com/solsw/generichelper"
)
// Reimplementing LINQ to Objects: Part 25 – ToDictionary
// https://codeblog.jonskeet.uk/2011/01/02/reimplementing-linq-to-objects-todictionary/
// https://learn.microsoft.com/dotnet/api/system.linq.enumerable.todictionary
// [ToMap] creates a [map] from an [Enumerable] according to a specified key selector function.
//
// [map]: https://go.dev/ref/spec#Map_types
// [ToMap]: https://learn.microsoft.com/dotnet/api/system.linq.enumerable.todictionary
func ToMap[Source any, Key comparable](source Enumerable[Source], keySelector func(Source) Key) (map[Key]Source, error) {
if source == nil {
return nil, ErrNilSource
}
if keySelector == nil {
return nil, ErrNilSelector
}
enr := source.GetEnumerator()
r := make(map[Key]Source)
for enr.MoveNext() {
c := enr.Current()
k := keySelector(c)
if _, ok := r[k]; ok {
return nil, ErrDuplicateKeys
}
r[k] = c
}
return r, nil
}
// ToMapMust is like [ToMap] but panics in case of error.
func ToMapMust[Source any, Key comparable](source Enumerable[Source], keySelector func(Source) Key) map[Key]Source {
return generichelper.Must(ToMap(source, keySelector))
}
// [ToMapSel] creates a [map] from an [Enumerable] according to specified key selector and element selector functions.
//
// Since Go's map does not support custom equaler to determine equality of the keys,
// LINQ's key comparer is not implemented.
// Similar to the keys equality functionality may be achieved using appropriate key selector.
// Example of custom key selector that mimics case-insensitive equaler for string keys
// is presented in [TestCustomSelector_string_string_int].
//
// [map]: https://go.dev/ref/spec#Map_types
// [ToMapSel]: https://learn.microsoft.com/dotnet/api/system.linq.enumerable.todictionary
func ToMapSel[Source any, Key comparable, Element any](source Enumerable[Source],
keySelector func(Source) Key, elementSelector func(Source) Element) (map[Key]Element, error) {
if source == nil {
return nil, ErrNilSource
}
if keySelector == nil || elementSelector == nil {
return nil, ErrNilSelector
}
enr := source.GetEnumerator()
r := make(map[Key]Element)
for enr.MoveNext() {
c := enr.Current()
k := keySelector(c)
if _, ok := r[k]; ok {
return nil, ErrDuplicateKeys
}
r[k] = elementSelector(c)
}
return r, nil
}
// ToMapSelMust is like [ToMapSel] but panics in case of error.
func ToMapSelMust[Source any, Key comparable, Element any](source Enumerable[Source],
keySelector func(Source) Key, elementSelector func(Source) Element) map[Key]Element {
return generichelper.Must(ToMapSel(source, keySelector, elementSelector))
}