@@ -49,6 +49,7 @@ defmodule Set do
49
49
defcallback intersection ( t , t ) :: t
50
50
defcallback member? ( t , value ) :: boolean
51
51
defcallback put ( t , value ) :: t
52
+ defcallback reduce ( t , Enumerable . acc , Enumerable . reducer ) :: Enumerable . result
52
53
defcallback size ( t ) :: non_neg_integer
53
54
defcallback subset? ( t , t ) :: boolean
54
55
defcallback to_list ( t ) :: list ( )
@@ -85,6 +86,10 @@ defmodule Set do
85
86
@ doc """
86
87
Returns a set that is `set1` without the members of `set2`.
87
88
89
+ Notice this function is polymorphic as it calculates the difference
90
+ for of any type. Each set implementation also provides a `difference`
91
+ function, but they can only work with sets of the same type.
92
+
88
93
## Examples
89
94
90
95
iex> Set.difference(HashSet.new([1,2]), HashSet.new([2,3,4])) |> Enum.sort
@@ -93,12 +98,25 @@ defmodule Set do
93
98
"""
94
99
@ spec difference ( t , t ) :: t
95
100
def difference ( set1 , set2 ) do
96
- target ( set1 ) . difference ( set1 , set2 )
101
+ target1 = target ( set1 )
102
+ target2 = target ( set2 )
103
+
104
+ if target1 == target2 do
105
+ target1 . difference ( set1 , set2 )
106
+ else
107
+ target2 . reduce set2 , { :cont , set1 } , fn v , acc ->
108
+ { :cont , target1 . delete ( acc , v ) }
109
+ end |> elem ( 1 )
110
+ end
97
111
end
98
112
99
113
@ doc """
100
114
Checks if `set1` and `set2` have no members in common.
101
115
116
+ Notice this function is polymorphic as it checks for disjoint sets of
117
+ any type. Each set implementation also provides a `disjoint?` function,
118
+ but they can only work with sets of the same type.
119
+
102
120
## Examples
103
121
104
122
iex> Set.disjoint?(HashSet.new([1, 2]), HashSet.new([3, 4]))
@@ -109,7 +127,19 @@ defmodule Set do
109
127
"""
110
128
@ spec disjoint? ( t , t ) :: boolean
111
129
def disjoint? ( set1 , set2 ) do
112
- target ( set1 ) . disjoint? ( set1 , set2 )
130
+ target1 = target ( set1 )
131
+ target2 = target ( set2 )
132
+
133
+ if target1 == target2 do
134
+ target1 . disjoint? ( set1 , set2 )
135
+ else
136
+ target2 . reduce ( set2 , { :cont , true } , fn member , acc ->
137
+ case target1 . member? ( set1 , member ) do
138
+ false -> { :cont , acc }
139
+ _ -> { :halt , false }
140
+ end
141
+ end ) |> elem ( 1 )
142
+ end
113
143
end
114
144
115
145
@doc """
@@ -121,7 +151,11 @@ defmodule Set do
121
151
end
122
152
123
153
@doc " ""
124
- Checks if `set1` and `set2 ` are equal .
154
+ Check if two sets are equal using `=== `.
155
+
156
+ Notice this function is polymorphic as it compares sets of
157
+ any type . Each set implementation also provides an `equal? `
158
+ function , but they can only work with sets of the same type .
125
159
126
160
## Examples
127
161
@@ -134,12 +168,28 @@ defmodule Set do
134
168
"""
135
169
@spec equal?(t, t) :: boolean
136
170
def equal?(set1, set2) do
137
- target(set1).equal?(set1, set2)
171
+ target1 = target(set1)
172
+ target2 = target(set2)
173
+
174
+ cond do
175
+ target1 == target2 ->
176
+ target1.equal?(set1, set2)
177
+
178
+ target1.size(set1) == target2.size(set2) ->
179
+ do_subset?(target1, target2, set1, set2)
180
+
181
+ true ->
182
+ false
183
+ end
138
184
end
139
185
140
186
@doc """
141
187
Returns a set containing only members in common between `set1` and `set2`.
142
188
189
+ Notice this function is polymorphic as it calculates the intersection of
190
+ any type. Each set implementation also provides a `intersection` function,
191
+ but they can only work with sets of the same type.
192
+
143
193
## Examples
144
194
145
195
iex> Set.intersection(HashSet.new([1,2]), HashSet.new([2,3,4])) |> Enum.sort
@@ -151,7 +201,16 @@ defmodule Set do
151
201
"""
152
202
@spec intersection( t, t ) :: t
153
203
def intersection ( set1 , set2 ) do
154
- target ( set1 ) . intersection ( set1 , set2 )
204
+ target1 = target ( set1 )
205
+ target2 = target ( set2 )
206
+
207
+ if target1 == target2 do
208
+ target1 . intersection ( set1 , set2 )
209
+ else
210
+ target1 . reduce set1 , { :cont , target1 . empty ( set1 ) } , fn v , acc ->
211
+ { :cont , if ( target2 . member? ( set2 , v ) , do: target1 . put ( acc , v ) , else: acc ) }
212
+ end |> elem ( 1 )
213
+ end
155
214
end
156
215
157
216
@ doc """
@@ -205,6 +264,10 @@ defmodule Set do
205
264
@ doc """
206
265
Checks if `set1`'s members are all contained in `set2`.
207
266
267
+ Notice this function is polymorphic as it checks the subset for
268
+ any type. Each set implementation also provides a `subset?` function,
269
+ but they can only work with sets of the same type.
270
+
208
271
## Examples
209
272
210
273
iex> Set.subset?(HashSet.new([1, 2]), HashSet.new([1, 2, 3]))
@@ -214,7 +277,14 @@ defmodule Set do
214
277
"""
215
278
@ spec subset? ( t , t ) :: boolean
216
279
def subset? ( set1 , set2 ) do
217
- target ( set1 ) . subset? ( set1 , set2 )
280
+ target1 = target ( set1 )
281
+ target2 = target ( set2 )
282
+
283
+ if target1 == target2 do
284
+ target1 . subset? ( set1 , set2 )
285
+ else
286
+ do_subset? ( target1 , target2 , set1 , set2 )
287
+ end
218
288
end
219
289
220
290
@ doc """
@@ -234,6 +304,10 @@ defmodule Set do
234
304
@ doc """
235
305
Returns a set containing all members of `set1` and `set2`.
236
306
307
+ Notice this function is polymorphic as it calculates the union of
308
+ any type. Each set implementation also provides a `union` function,
309
+ but they can only work with sets of the same type.
310
+
237
311
## Examples
238
312
239
313
iex> Set.union(HashSet.new([1,2]), HashSet.new([2,3,4])) |> Enum.sort
@@ -242,7 +316,25 @@ defmodule Set do
242
316
"""
243
317
@ spec union ( t , t ) :: t
244
318
def union ( set1 , set2 ) do
245
- target ( set1 ) . union ( set1 , set2 )
319
+ target1 = target ( set1 )
320
+ target2 = target ( set2 )
321
+
322
+ if target1 == target2 do
323
+ target1 . union ( set1 , set2 )
324
+ else
325
+ target2 . reduce set2 , { :cont , set1 } , fn v , acc ->
326
+ { :cont , target1 . put ( acc , v ) }
327
+ end |> elem ( 1 )
328
+ end
329
+ end
330
+
331
+ defp do_subset?( target1, target2, set1, set2) do
332
+ target1. reduce ( set1 , { :cont , true } , fn member , acc ->
333
+ case target2 . member? ( set2 , member ) do
334
+ true -> { :cont , acc }
335
+ _ -> { :halt , false }
336
+ end
337
+ end ) |> elem ( 1 )
246
338
end
247
339
248
340
defp unsupported_set ( set ) do
0 commit comments