1 #Region "Microsoft.VisualBasic::79d52670329177b5acd2b3290ba94fe3, Microsoft.VisualBasic.Core\ComponentModel\DataStructures\Set\Set.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Class [Set]
35     
36     '         Properties: IsEmpty, Length
37     
38     '         Constructor: (+4 OverloadsSub New
39     
40     '         Function: Contains, Equals, GetHashCode, IEnumerable_GetEnumerator, Remove
41     '                   ToArray, ToString
42     
43     '         Sub: Add, Clear, Dispose
44     
45     '         Operators: -, +, <>, =, (+2 OverloadsAnd
46     '                    (+4 OverloadsOr
47     
48     
49     ' /********************************************************************************/
50
51 #End Region
52
53 Imports System.Runtime.CompilerServices
54 Imports Microsoft.VisualBasic.Language.Default
55 Imports Microsoft.VisualBasic.Scripting.MetaData
56
57 Namespace ComponentModel.DataStructures
58
59     ''' <summary>
60     ''' Represents an unordered grouping of unique hetrogenous members.
61     ''' (这个对象的功能和List类似,但是这个对象的主要的作用是进行一些集合运算:使用AND求交集以及使用OR求并集的)
62     ''' </summary>
63     ''' 
64     <Package("Set",
65              Category:=APICategories.UtilityTools,
66              Description:="Represents an unordered grouping of unique hetrogenous members.",
67              Url:="http://www.codeproject.com/Articles/10806/A-Generic-Set-Data-Structure",
68              Publisher:="Sean Michael Murphy")>
69     Public Class [Set]
70         Implements IEnumerable
71         Implements IDisposable
72         Implements IsEmpty
73
74 #Region "Private Members"
75         Protected Friend _members As New ArrayList()
76         Protected _behaviour As BadBehaviourResponses = BadBehaviourResponses.BeAggressive
77         ''' <summary>
78         ''' 如何判断两个元素是否相同?
79         ''' </summary>
80         Protected Friend _equals As Func(Of ObjectObjectBoolean)
81 #End Region
82
83 #Region "ctors"
84         ''' <summary>
85         ''' Default constructor.
86         ''' </summary>
87         Public Sub New(Optional equals As Func(Of ObjectObjectBoolean) = Nothing)
88             _equals = equals
89         End Sub
90
91         Protected Sub New()
92             _behaviour = BadBehaviourResponses.BeAggressive
93         End Sub
94
95         ''' <summary>
96         ''' Constructor called when the source data is an array of <see cref="[Set]">Sets</see>.  They will
97         ''' be unioned together, with addition exceptions quietly eaten.
98         ''' </summary>
99         ''' <param name="sources">The source array of <see cref="[Set]">Set</see> objects.</param>
100         Public Sub New(sources As [Set](), Optional equals As Func(Of ObjectObjectBoolean) = Nothing)
101             _behaviour = BadBehaviourResponses.BeCool
102             _equals = equals
103
104             For Each initialSet As [Set] In sources
105                 For Each o As Object In initialSet
106                     Call Me.Add(o)
107                 Next
108             Next
109
110             _behaviour = BadBehaviourResponses.BeAggressive
111         End Sub
112
113         Sub New(source As IEnumerable, Optional equals As Func(Of ObjectObjectBoolean) = Nothing)
114             _behaviour = BadBehaviourResponses.BeCool
115             _equals = equals
116
117             For Each o As Object In source
118                 Call Me.Add(o)
119             Next
120
121             _behaviour = BadBehaviourResponses.BeAggressive
122         End Sub
123 #End Region
124
125 #Region "Public Methods"
126         ''' <summary>
127         ''' Empty the set of all members.
128         ''' </summary>
129         Public Sub Clear()
130             _members.Clear()
131         End Sub
132
133         ''' <summary>
134         ''' A method to determine whether the <see cref="[Set]">Set</see> has members.
135         ''' </summary>
136         ''' <returns>True is there are members, false if there are 0 members.</returns>
137         Public ReadOnly Property IsEmpty() As Boolean Implements IsEmpty.IsEmpty
138             <MethodImpl(MethodImplOptions.AggressiveInlining)>
139             Get
140                 Return _members.Count = 0
141             End Get
142         End Property
143
144         ''' <summary>
145         ''' Remove a member from the <see cref="[Set]">Set</see>.
146         ''' </summary>
147         ''' <param name="target">The member to remove.</param>
148         ''' <returns>True if a member was removed, false if nothing was found that 
149         ''' was removed.</returns>
150         Public Function Remove(target As ObjectAs Boolean
151             For i As Int32 = 0 To _members.Count - 1
152                 If _equals(_members(i), target) Then
153                     _members.RemoveAt(i)
154                     Return True
155                 End If
156             Next
157
158             Return False
159         End Function
160
161         ''' <summary>
162         ''' Method to add an <see cref="Object">Object</see> to the set.  The new member 
163         ''' must be unique.
164         ''' </summary>
165         ''' <param name="member"><see cref="Object">Object</see> to add.</param>
166         ''' <exception cref="InvalidOperationException">If the member being added is
167         ''' already a member of the set an InvalidOperationException is thrown.</exception>
168         Public Sub Add(member As Object)
169             For i As Int32 = 0 To _members.Count - 1
170                 If _equals(_members(i), member) Then
171                     If _behaviour = BadBehaviourResponses.BeAggressive Then
172                         Throw New ArgumentException(member.ToString() + " already in set in position " + (i + 1).ToString() + ".")
173                     Else
174                         Return
175                     End If
176                 End If
177             Next
178
179             _members.Add(member)
180         End Sub
181
182         ''' <summary>
183         ''' Method to determine if a given object is a member of the set.
184         ''' </summary>
185         ''' <param name="target">The object to look for in the set.</param>
186         ''' <returns>True if it is a member of the <see cref="[Set]">Set</see>, false if not.</returns>
187         Public Function Contains(target As ObjectAs Boolean
188             For Each o As Object In _members
189                 If _equals(o, target) Then
190                     Return True
191                 End If
192             Next
193
194             Return False
195         End Function
196
197         ''' <summary>
198         ''' Copies the members of the <see cref="[Set]">Set</see> to an array of 
199         ''' <see cref="Object">Objects</see>.
200         ''' </summary>
201         ''' <returns>An <see cref="Object">Object</see> array copies of the 
202         ''' elements of the <see cref="[Set]">Set</see></returns>
203         Public Function ToArray() As Object()
204             Return _members.ToArray()
205         End Function
206 #End Region
207
208 #Region "Accessor"
209         ''' <summary>
210         ''' Public accessor for the members of the <see cref="[Set]">Set</see>.
211         ''' </summary>
212         Default Public ReadOnly Property Item(index As Int32) As Object
213             <MethodImpl(MethodImplOptions.AggressiveInlining)>
214             Get
215                 Return _members(index)
216             End Get
217         End Property
218 #End Region
219
220         ''' <summary>
221         ''' The number of members of the set.
222         ''' </summary>
223         Public ReadOnly Property Length() As Int32
224             <MethodImpl(MethodImplOptions.AggressiveInlining)>
225             Get
226                 Return _members.Count
227             End Get
228         End Property
229
230 #Region "Overloaded Operators"
231         ''' <summary>
232         ''' If the Set is created by casting an array to it, add the members of
233         ''' the array through the Add method, so if the array has dupes an error
234         ''' will occur.
235         ''' </summary>
236         ''' <param name="array">The array with the objects to initialize the array.</param>
237         ''' <returns>A new Set object based on the members of the array.</returns>
238         ''' <exception cref="InvalidCastException">If the array contains duplicate
239         ''' elements, an InvalidCastException will result.</exception>
240         Public Shared Narrowing Operator CType(array As Array) As [Set]
241             Dim s As New [Set]()
242
243             For Each o As [Object] In array
244                 Try
245                     s.Add(o)
246                 Catch e As ArgumentException
247                     Throw New InvalidCastException("Array contained duplicates and can't be cast to a Set.", e)
248                 End Try
249             Next
250
251             Return s
252         End Operator
253
254         ''' <summary>
255         ''' Performs a union of two sets. The elements can exists 
256         ''' in <paramref name="s1"/> or <paramref name="s2"/>.
257         ''' (求并集)
258         ''' </summary>
259         ''' <param name="s1">Any set.</param>
260         ''' <param name="s2">Any set.</param>
261         ''' <returns>A new <see cref="[Set]">Set</see> object that contains all of the
262         ''' members of each of the input sets.</returns>
263         ''' 
264         <MethodImpl(MethodImplOptions.AggressiveInlining)>
265         Public Shared Operator Or(s1 As [Set], s2 As [Set]) As [Set]
266             Return New [Set](s1.ToArray + s2.ToArray.AsList, s1._equals)
267         End Operator
268
269         Public Shared Operator Or(s1 As [Set], s2 As IEnumerable) As [Set]
270             Dim sb As New [Set](s2, s1._equals)
271             Return s1 Or sb
272         End Operator
273
274         ''' <summary>
275         ''' Performs an intersection of two sets, the elements should exists 
276         ''' in <paramref name="s1"/> and <paramref name="s2"/>.
277         ''' (求交集)
278         ''' </summary>
279         ''' <param name="s1">Any set.</param>
280         ''' <param name="s2">Any set.</param>
281         ''' <returns>A new <see cref="[Set]">Set</see> object that contains the members
282         ''' that were common to both of the input sets.</returns>
283         Public Shared Operator And(s1 As [Set], s2 As [Set]) As [Set]
284             Dim result As New [Set](s1._equals)
285
286             result._behaviour = BadBehaviourResponses.BeCool
287
288             If s1.Length > s2.Length Then
289                 For Each o As Object In s1
290                     If s2.Contains(o) Then
291                         result.Add(o)
292                     End If
293                 Next
294             Else
295                 For Each o As Object In s2
296                     If s1.Contains(o) Then
297                         result.Add(o)
298                     End If
299                 Next
300             End If
301
302             result._behaviour = BadBehaviourResponses.BeAggressive
303
304             Return result
305         End Operator
306
307         ''' <summary>
308         ''' 求两个集合的并集,将两个集合之中的所有元素都合并在一起,这个操作符会忽略掉重复出现的元素
309         ''' </summary>
310         ''' <param name="s1"></param>
311         ''' <param name="s2"></param>
312         ''' <returns></returns>
313         Public Shared Operator +(s1 As [Set], s2 As [Set]) As [Set]
314             Return s1 Or s2
315         End Operator
316
317         ''' <summary>
318         ''' except(差集)集合运算:先将其中完全重复的数据行删除,再返回只在第一个集合中出现,在第二个集合中不出现的所有行。
319         ''' </summary>
320         ''' <param name="s1"></param>
321         ''' <param name="s2"></param>
322         ''' <returns></returns>
323         Public Shared Operator -(s1 As [Set], s2 As [Set]) As [Set]
324             Dim inter As [Set] = s1 And s2  ' 交集
325
326             For Each x In inter      ' 将集合1之中所有的交集元素移除即可
327                 Call s1.Remove(x)
328             Next
329
330             Return s1
331         End Operator
332
333         ''' <summary>
334         ''' Overloaded == operator to determine if 2 sets are equal.
335         ''' </summary>
336         ''' <param name="s1">Any set.</param>
337         ''' <param name="s2">Any set.</param>
338         ''' <returns>True if the two comparison sets have the same number of elements, and
339         ''' all of the elements of set s1 are contained in s2.</returns>
340         Public Shared Operator =(s1 As [Set], s2 As [Set]) As Boolean
341             If s1.Length <> s2.Length Then
342                 Return False
343             End If
344
345             For Each o As Object In s1
346                 If Not s2.Contains(o) Then
347                     Return False
348                 End If
349             Next
350
351             Return True
352         End Operator
353
354         ''' <summary>
355         ''' Overloaded != operator to determine if 2 sets are unequal.
356         ''' </summary>
357         ''' <param name="s1">A benchmark set.</param>
358         ''' <param name="s2">The set to compare against the benchmark.</param>
359         ''' <returns>True if the two comparison sets fail the equality (==) test,
360         ''' false if the pass the equality test.</returns>
361         Public Shared Operator <>(s1 As [Set], s2 As [Set]) As Boolean
362             Return Not (s1 = s2)
363         End Operator
364 #End Region
365
366 #Region "Overridden Members"
367         ''' <summary>
368         ''' Determines whether two <see cref="[Set]">Set</see> instances are equal.
369         ''' </summary>
370         ''' <param name="obj">The <see cref="[Set]">Set</see> to compare to the current Set.</param>
371         ''' <returns>true if the specified <see cref="[Set]">Set</see> is equal to the current 
372         ''' Set; otherwise, false.</returns>
373         Public Overrides Function Equals(obj As ObjectAs Boolean
374             Dim o As [Set] = TryCast(obj, [Set])
375
376             If obj Is Nothing Then
377                 Return False
378             End If
379
380             Return (Me Is o)
381         End Function
382
383         ''' <summary>
384         ''' Serves as a hash function for a particular type, suitable for use in hashing 
385         ''' algorithms and data structures like a hash table.
386         ''' </summary>
387         ''' <returns>A hash code for the current <see cref="[Set]">Set</see>.</returns>
388         <MethodImpl(MethodImplOptions.AggressiveInlining)>
389         Public Overrides Function GetHashCode() As Integer
390             Return MyBase.GetHashCode()
391         End Function
392
393         ''' <summary>
394         ''' Returns a <see cref="String">String</see> that represents the current
395         ''' <see cref="[Set]">Set</see>.
396         ''' </summary>
397         ''' <returns>A <see cref="String">String</see> that represents the current
398         ''' <see cref="[Set]">Set</see>.</returns>
399         Public Overrides Function ToString() As String
400             Dim contents$ =
401                 (From o As Object In _members Select Scripting.ToString(o)) _
402                 .JoinBy(", ")
403             Return $"{{ {contents} }}"
404         End Function
405 #End Region
406
407         ''' <summary>
408         ''' Returns an enumerator that can iterate through a collection.
409         ''' </summary>
410         ''' <returns>An <see cref="IEnumerator">IEnumerator</see> that can be 
411         ''' used to iterate through the collection.</returns>
412         Private Iterator Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
413             For Each x As Object In Me._members
414                 Yield x
415             Next
416         End Function
417
418         ''' <summary>
419         ''' Performs cleanup tasks on the <see cref="[Set]">Set</see> object.
420         ''' </summary>
421         <MethodImpl(MethodImplOptions.AggressiveInlining)>
422         Public Sub Dispose() Implements IDisposable.Dispose
423             _members.Clear()
424         End Sub
425     End Class
426 End Namespace