forked from samber/lo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
intersect.go
177 lines (143 loc) · 3.79 KB
/
intersect.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package lo
// Contains returns true if an element is present in a collection.
func Contains[T comparable](collection []T, element T) bool {
for _, item := range collection {
if item == element {
return true
}
}
return false
}
// ContainsBy returns true if predicate function return true.
func ContainsBy[T any](collection []T, predicate func(T) bool) bool {
for _, item := range collection {
if predicate(item) {
return true
}
}
return false
}
// Every returns true if all elements of a subset are contained into a collection or if the subset is empty.
func Every[T comparable](collection []T, subset []T) bool {
for _, elem := range subset {
if !Contains(collection, elem) {
return false
}
}
return true
}
// EveryBy returns true if the predicate returns true for all of the elements in the collection or if the collection is empty.
func EveryBy[V any](collection []V, predicate func(V) bool) bool {
for _, v := range collection {
if !predicate(v) {
return false
}
}
return true
}
// Some returns true if at least 1 element of a subset is contained into a collection.
// If the subset is empty Some returns false.
func Some[T comparable](collection []T, subset []T) bool {
for _, elem := range subset {
if Contains(collection, elem) {
return true
}
}
return false
}
// SomeBy returns true if the predicate returns true for any of the elements in the collection.
// If the collection is empty SomeBy returns false.
func SomeBy[V any](collection []V, predicate func(V) bool) bool {
for _, v := range collection {
if predicate(v) {
return true
}
}
return false
}
// None returns true if no element of a subset are contained into a collection or if the subset is empty.
func None[V comparable](collection []V, subset []V) bool {
for _, elem := range subset {
if Contains(collection, elem) {
return false
}
}
return true
}
// NoneBy returns true if the predicate returns true for none of the elements in the collection or if the collection is empty.
func NoneBy[V any](collection []V, predicate func(V) bool) bool {
for _, v := range collection {
if predicate(v) {
return false
}
}
return true
}
// Intersect returns the intersection between two collections.
func Intersect[T comparable](list1 []T, list2 []T) []T {
result := []T{}
seen := map[T]struct{}{}
for _, elem := range list1 {
seen[elem] = struct{}{}
}
for _, elem := range list2 {
if _, ok := seen[elem]; ok {
result = append(result, elem)
}
}
return result
}
// Difference returns the difference between two collections.
// The first value is the collection of element absent of list2.
// The second value is the collection of element absent of list1.
func Difference[T comparable](list1 []T, list2 []T) ([]T, []T) {
left := []T{}
right := []T{}
seenLeft := map[T]struct{}{}
seenRight := map[T]struct{}{}
for _, elem := range list1 {
seenLeft[elem] = struct{}{}
}
for _, elem := range list2 {
seenRight[elem] = struct{}{}
}
for _, elem := range list1 {
if _, ok := seenRight[elem]; !ok {
left = append(left, elem)
}
}
for _, elem := range list2 {
if _, ok := seenLeft[elem]; !ok {
right = append(right, elem)
}
}
return left, right
}
// Union returns all distinct elements from both collections.
// result returns will not change the order of elements relatively.
func Union[T comparable](list1 []T, list2 []T) []T {
result := []T{}
seen := map[T]struct{}{}
hasAdd := map[T]struct{}{}
for _, e := range list1 {
seen[e] = struct{}{}
}
for _, e := range list2 {
seen[e] = struct{}{}
}
for _, e := range list1 {
if _, ok := seen[e]; ok {
result = append(result, e)
hasAdd[e] = struct{}{}
}
}
for _, e := range list2 {
if _, ok := hasAdd[e]; ok {
continue
}
if _, ok := seen[e]; ok {
result = append(result, e)
}
}
return result
}