1
+ var numbers = require ( '../numbers' ) ,
2
+ exports = Set ;
3
+
4
+ //TODO Determine where _getValid and _getValidElement can go.
5
+ /**
6
+ * Get the information in a valid form according to the {Set} API.
7
+ *
8
+ * @param {Array|Number } Data or set of elements
9
+ * @param {Object } object to determine which test.
10
+ */
11
+ function _getValid ( data , obj ) {
12
+ if ( Set . prototype . isPrototypeOf ( obj ) ) {
13
+ if ( Object . prototype . toString . call ( data ) === '[object Array]' ) {
14
+ return data ; //TODO map getValidElement.
15
+ } else {
16
+ return [ data ] ;
17
+ }
18
+ }
19
+ else {
20
+ throw new Error ( obj . constructor + " is currently not supported in _getValid." ) ;
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Get the elements in a valid form according to the {Set} API.
26
+ *
27
+ * @param {Array|Number } Element
28
+ * @param {Object } object to determine which test.
29
+ */
30
+ function _getValidElement ( d , obj ) {
31
+ if ( Set . prototype . isPrototypeOf ( obj ) ) {
32
+ // currently only support numbers
33
+ // If hashing is implemented, it should be hashed here and rehashed in toArray
34
+ if ( d % 1 === 0 ) return '' + d ;
35
+ else throw new Error ( d + " is not a valid element for a Set" ) ;
36
+ }
37
+ else {
38
+ throw new Error ( obj . constructor + " is currently not supported in _getValidElement." ) ;
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Core Data Structure for use in numbers.js library.
44
+ * This data structure implements a set (with similar API to
45
+ * that of python's set data structure).
46
+ *
47
+ * @param {Number|Array } (optional) values to add to initial Set object.
48
+ */
49
+ var Set = function ( data ) {
50
+ if ( arguments . length === 0 ) {
51
+ this . data = { } ;
52
+ }
53
+ else {
54
+ data = _getValid ( data , this ) ; //returns array
55
+ this . data = { } ;
56
+ var l = this . length ,
57
+ i ;
58
+ for ( i = 0 ; i < l ; i ++ ) {
59
+ this . add ( data [ i ] ) ;
60
+ }
61
+ }
62
+ } ;
63
+
64
+ /**
65
+ * Determine if the Set has value(s).
66
+ *
67
+ * @param {Number|Array } Value(s) added to set
68
+ * @return {Boolean|Array } Returns a boolean array or boolean value
69
+ */
70
+ Set . prototype . has = function ( d ) {
71
+ if ( Object . prototype . toString . call ( d ) === '[object Array]' ) {
72
+ var i ,
73
+ l = d . length ,
74
+ ret = [ ] ;
75
+ for ( i = 0 ; i < l ; i ++ ) {
76
+ ret . push ( this . has ( d [ i ] ) ) ;
77
+ }
78
+ return ret ;
79
+ }
80
+ else {
81
+ d = _getValidElement ( d , this ) ;
82
+ return this . data . hasOwnProperty ( d ) ;
83
+ }
84
+ } ;
85
+
86
+ /**
87
+ * Create a copy of the Set.
88
+ *
89
+ * @return {Set } an exact copy of this set.
90
+ */
91
+ Set . prototype . clone = function ( ) {
92
+ return new Set ( this . toArray ( ) ) ; //TODO proper copy
93
+ } ;
94
+
95
+ /**
96
+ * Determine if all values in B are in this set.
97
+ *
98
+ * @param {Set|Array } Set B or array to create set from
99
+ * @return {Boolean } true for superset
100
+ */
101
+ Set . prototype . isSuperSet = function ( B ) {
102
+ if ( ! Set . prototype . isPrototypeOf ( B ) )
103
+ B = new Set ( _getValid ( B , this ) ) ;
104
+ return this . has ( B . toArray ( ) ) . reduce ( function ( a , b ) {
105
+ return ! ! a && ! ! b ;
106
+ } ) ;
107
+ } ;
108
+
109
+ /**
110
+ * Determine if all values in this set are in B.
111
+ *
112
+ * @param {Set|Array } Set B or array to create set from
113
+ * @return { }
114
+ */
115
+ Set . prototype . isSubSet = function ( B ) {
116
+ if ( ! Set . prototype . isPrototypeOf ( B ) )
117
+ B = new Set ( _getValid ( B , this ) ) ;
118
+ return B . has ( this . toArray ( ) ) . reduce ( function ( a , b ) {
119
+ return ! ! a && ! ! b ;
120
+ } ) ;
121
+ } ;
122
+
123
+ /**
124
+ * Convert this Set to an Array
125
+ *
126
+ * @param {Function } (optional) the function in which to sort the array by
127
+ * @return {Array } Array of elements in set.
128
+ */
129
+ Set . prototype . toArray = function ( sortFunc ) {
130
+ var ret = Object . keys ( this . data ) ;
131
+ ret . map ( function ( a ) { return + a ; } ) ; //currently supports only numbers
132
+ if ( arguments . length === 1 ) ret . sort ( sortFunc ) ;
133
+ return ret ;
134
+ } ;
135
+
136
+ /**
137
+ * Add value(s) to this Set.
138
+ * (A + B)
139
+ *
140
+ * @param {Number|Array } Value(s) added to set
141
+ * @return {Set } Updated Set
142
+ */
143
+ Set . prototype . add = function ( d ) {
144
+ if ( Object . prototype . toString . call ( d ) === '[object Array]' ) {
145
+ var i ,
146
+ l = d . length ;
147
+ for ( i = 0 ; i < l ; i ++ ) {
148
+ this . add ( d [ i ] ) ;
149
+ }
150
+ }
151
+ else {
152
+ d = _getValidElement ( d , this ) ;
153
+ if ( ! this . has ( d ) ) {
154
+ this . data [ d ] = true ;
155
+ this . size ++ ;
156
+ }
157
+ }
158
+ return this ;
159
+ } ;
160
+
161
+ /**
162
+ * Remove value(s) from this Set.
163
+ * (A - B)
164
+ *
165
+ * @param {Number|Array } Value(s) removed from set
166
+ * @return {Set } Updated Set
167
+ */
168
+ Set . prototype . remove = function ( d ) {
169
+ if ( Object . prototype . toString . call ( d ) === '[object Array]' ) {
170
+ var i ,
171
+ l = d . length ,
172
+ ret = [ ] ;
173
+ for ( i = 0 ; i < l ; i ++ ) {
174
+ ret . push ( this . remove ( d [ i ] ) ) ;
175
+ }
176
+ return ret ;
177
+ }
178
+ else {
179
+ d = _getValidElement ( d , this ) ;
180
+ if ( this . has ( d ) ) {
181
+ delete this . data [ d ] ;
182
+ this . size -- ;
183
+ return true ;
184
+ }
185
+ return false ;
186
+ }
187
+ } ;
188
+
189
+ /**
190
+ * Add any elements from B that are not already in A.
191
+ * (A | B)
192
+ *
193
+ * @param {Set|Array } the set or data to create a set from
194
+ * @return {Set } Updated Set
195
+ */
196
+ Set . prototype . union = function ( B ) {
197
+ if ( ! Set . prototype . isPrototypeOf ( B ) )
198
+ B = new Set ( _getValid ( B , this ) ) ;
199
+ return this . add ( B . toArray ( ) ) ;
200
+ } ;
201
+
202
+ /**
203
+ * Creates an updated set containing elements which are both in this and in B.
204
+ * (A & B)
205
+ *
206
+ * @param {Set|Array } the set or data to create a set from
207
+ * @return {Set } Updated Set
208
+ */
209
+ Set . prototype . intersection = function ( B ) {
210
+ if ( ! Set . prototype . isPrototypeOf ( B ) )
211
+ B = new Set ( _getValid ( B , this ) ) ;
212
+ var BList = B . toArray ( ) ,
213
+ check = this . has ( BList ) ,
214
+ i ,
215
+ l = BList . length ,
216
+ commonList = [ ] ;
217
+ for ( i = 0 ; i < l ; i ++ ) {
218
+ if ( check [ i ] )
219
+ commonList . push ( BList [ i ] ) ;
220
+ }
221
+ this = new Set ( commonList ) ;
222
+ return this ;
223
+ } ;
224
+
225
+ /**
226
+ * Removes all elements in this set that are also in set B.
227
+ * (A - B)
228
+ *
229
+ * @param {Set|Array } the set or data to create a set from
230
+ * @return {Set } Updated Set
231
+ */
232
+ Set . prototype . difference = function ( B ) {
233
+ if ( ! Set . prototype . isPrototypeOf ( B ) )
234
+ B = new Set ( _getValid ( B , this ) ) ;
235
+ var AList = this . toArray ( ) ,
236
+ check = B . has ( AList ) , //TODO all should also accept sets
237
+ i ,
238
+ l = AList . length ,
239
+ differenceList = [ ] ;
240
+ for ( i = 0 ; i < l ; i ++ ) {
241
+ if ( ! check [ i ] )
242
+ differenceList . push ( AList [ i ] ) ;
243
+ }
244
+ //TODO not right
245
+ this = new Set ( differenceList ) ;
246
+ return this ;
247
+ } ;
248
+
249
+ /**
250
+ * Update set to only include elements not in A and not in B.
251
+ * (A | B) - (A & B)
252
+ * A + B - (A & B)
253
+ *
254
+ * @param {Set|Array } the set or data to create a set from
255
+ * @return {Set } Updated Set
256
+ */
257
+ Set . prototype . symmetricDifference = function ( B ) {
258
+ if ( ! Set . prototype . isPrototypeOf ( B ) )
259
+ B = new Set ( _getValid ( B , this ) ) ;
260
+ var BAdded = B . difference ( this . clone ( )
261
+ . intersection ( B ) )
262
+ . toArray ( ) ; //needs to accept sets
263
+ this . difference ( this . clone ( )
264
+ . intersection ( B ) ) ;
265
+ return this . add ( BAdded ) ;
266
+ } ;
267
+
268
+ /**
269
+ * Non-modified static wrapper of Set.prototype.add()
270
+ *
271
+ * @param {Set|Array } the set or data to create a set from
272
+ * @param {Number|Array } values to add to the set.
273
+ * @return {Set } A copy or created Set with updates made.
274
+ */
275
+ Set . add = function ( A , d ) {
276
+ if ( ! Set . prototype . isPrototypeOf ( A ) )
277
+ A = new Set ( _getValid ( A , this ) ) ;
278
+ return A . clone ( )
279
+ . add ( d ) ;
280
+ } ;
281
+
282
+ /**
283
+ * Non-modified static wrapper of Set.prototype.remove()
284
+ *
285
+ * @param {Set|Array } the set or data to create a set from
286
+ * @param {Number|Array } values to add to the set.
287
+ * @return {Set } A copy or created Set with updates made.
288
+ */
289
+ Set . remove = function ( A , d ) {
290
+ if ( ! Set . prototype . isPrototypeOf ( A ) )
291
+ A = new Set ( _getValid ( A , this ) ) ;
292
+ var newA = A . clone ( ) ,
293
+ newA . remove ( d ) ;
294
+ return newA ;
295
+ } ;
296
+
297
+ /**
298
+ * Non-modified static wrapper of Set.prototype.union()
299
+ *
300
+ * @param {Set|Array } the set or data to create a set from
301
+ * @param {Set|Array } the set to union with A, or data to create set from
302
+ * @return {Set } A copy or created Set with updates made.
303
+ */
304
+ Set . union = function ( A , B ) {
305
+ if ( ! Set . prototype . isPrototypeOf ( A ) )
306
+ A = new Set ( _getValid ( A , this ) ) ;
307
+ return A . clone ( )
308
+ . union ( B ) ;
309
+ } ;
310
+
311
+ /**
312
+ * Non-modified static wrapper of Set.prototype.intersection()
313
+ *
314
+ * @param {Set|Array } the set or data to create a set from
315
+ * @param {Set|Array } the set to union with A, or data to create set from
316
+ * @return {Set } A copy or created Set with updates made.
317
+ */
318
+ Set . intersection = function ( A , B ) {
319
+ if ( ! Set . prototype . isPrototypeOf ( A ) )
320
+ A = new Set ( _getValid ( A , this ) ) ;
321
+ return A . clone ( )
322
+ . intersection ( B ) ;
323
+ } ;
324
+
325
+ /**
326
+ * Non-modified static wrapper of Set.prototype.union()
327
+ *
328
+ * @param {Set|Array } the set or data to create a set from
329
+ * @param {Set|Array } the set to union with A, or data to create set from
330
+ * @return {Set } A copy or created Set with updates made.
331
+ */
332
+ Set . difference = function ( A , B ) {
333
+ if ( ! Set . prototype . isPrototypeOf ( A ) )
334
+ A = new Set ( _getValid ( A , this ) ) ;
335
+ return A . clone ( )
336
+ . difference ( B ) ;
337
+ } ;
338
+
339
+ /**
340
+ * Non-modified static wrapper of Set.prototype.union()
341
+ *
342
+ * @param {Set|Array } the set or data to create a set from
343
+ * @param {Set|Array } the set to union with A, or data to create set from
344
+ * @return {Set } A copy or created Set with updates made.
345
+ */
346
+
347
+
348
+
349
+ Set . symmetricDifference = function ( A , B ) {
350
+ if ( ! Set . prototype . isPrototypeOf ( A ) )
351
+ A = new Set ( _getValid ( A , this ) ) ;
352
+ return A . clone ( )
353
+ . symmetricDifference ( B ) ;
354
+ } ;
0 commit comments