1 #Region "Microsoft.VisualBasic::8ea134180a40bffae99e68390d983785, Microsoft.VisualBasic.Core\Extensions\Collection\Enumerable.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     Module IEnumerations
35     
36     '     Function: [Next], CreateDictionary, (+2 Overloads) Differ, (+2 Overloads) FindByItemKey, FindByItemValue
37     '               (+2 OverloadsGetItem, GetItems, Take, (+2 Overloads) Takes, ToDictionary
38     '               ToEntryDictionary
39     
40     ' /********************************************************************************/
41
42 #End Region
43
44 Imports System.Runtime.CompilerServices
45 Imports Microsoft.VisualBasic.ComponentModel.Collection
46 Imports Microsoft.VisualBasic.ComponentModel.Collection.Generic
47 Imports Microsoft.VisualBasic.Language
48 Imports Microsoft.VisualBasic.Serialization.JSON
49 Imports Microsoft.VisualBasic.Text.Xml.Models
50 Imports Microsoft.VisualBasic.Text.Xml.Models.KeyValuePair
51
52 <Extension>
53 Public Module IEnumerations
54
55     ''' <summary>
56     ''' Get a random element
57     ''' </summary>
58     ''' <typeparam name="T"></typeparam>
59     ''' <param name="random"></param>
60     ''' <param name="data"></param>
61     ''' <returns></returns>
62     <MethodImpl(MethodImplOptions.AggressiveInlining)>
63     <Extension>
64     Public Function [Next](Of T)(random As Random, data As T()) As T
65         Return data(random.Next(0, data.Length))
66     End Function
67
68     <Extension> Public Function Differ(Of T As INamedValue, T2)(source As IEnumerable(Of T),
69                                                                 ToDiffer As IEnumerable(Of T2),
70                                                                 getId As Func(Of T2, String)) As String()
71
72         Dim targetIndex As String() = (From item As T In source Select item.Key).ToArray
73         Dim LQuery$() = LinqAPI.Exec(Of String) _
74  _
75             () <= From item As T2
76                   In ToDiffer
77                   Let strId As String = getId(item)
78                   Where Array.IndexOf(targetIndex, strId) = -1
79                   Select strId
80
81         Return LQuery
82     End Function
83
84     <Extension> Public Function Differ(Of T As INamedValue, T2 As INamedValue)(source As IEnumerable(Of T), ToDiffer As IEnumerable(Of T2)) As String()
85         Dim targetIndex As String() = (From item In source Select item.Key).ToArray
86         Dim LQuery = (From item As T2
87                       In ToDiffer
88                       Where Array.IndexOf(targetIndex, item.Key) = -1
89                       Select item.Key).ToArray
90         Return LQuery
91     End Function
92
93     <Extension>
94     Public Function GetItem(Of T As INamedValue)(Id As String, source As IEnumerable(Of T)) As T
95         Return source.Take(Id)
96     End Function
97
98     <Extension> Public Function GetItems(Of T As INamedValue)(source As IEnumerable(Of T), Id As StringAs T()
99         Dim LQuery = (From ItemObj As T In source Where String.Equals(Id, ItemObj.Key) Select ItemObj).ToArray
100         Return LQuery
101     End Function
102
103     ''' <summary>
104     ''' 将目标集合对象转换为一个字典对象
105     ''' </summary>
106     ''' <typeparam name="T"></typeparam>
107     ''' <param name="Collection"></param>
108     ''' <returns></returns>
109     ''' <remarks></remarks>
110     <Extension> Public Function CreateDictionary(Of T As INamedValue)(Collection As IEnumerable(Of T)) As Dictionary(Of String, T)
111         Dim Dictionary As New Dictionary(Of String, T)
112
113         For Each obj In Collection
114             Call Dictionary.Add(obj.Key, obj)
115         Next
116
117         Return Dictionary
118     End Function
119
120     <Extension> Public Function FindByItemKey(source As IEnumerable(Of KeyValuePair), Key As StringOptional Explicit As Boolean = TrueAs KeyValuePair()
121         Dim Method = If(Explicit, StringComparison.Ordinal, StringComparison.OrdinalIgnoreCase)
122         Dim LQuery = (From item In source Where String.Equals(item.Key, Key, Method) Select item).ToArray
123         Return LQuery
124     End Function
125
126     <Extension> Public Function FindByItemKey(Of PairItemType As IKeyValuePair)(source As IEnumerable(Of PairItemType), Key As StringOptional Explicit As Boolean = TrueAs PairItemType()
127         Dim Method = If(Explicit, StringComparison.Ordinal, StringComparison.OrdinalIgnoreCase)
128         Dim LQuery = (From item In source Where String.Equals(item.Key, Key, Method) Select item).ToArray
129         Return LQuery
130     End Function
131
132     <Extension> Public Function FindByItemValue(Of PairItemType As IKeyValuePair)(source As IEnumerable(Of PairItemType), Value As StringOptional strict As Boolean = TrueAs PairItemType()
133         Dim Method = If(strict, StringComparison.Ordinal, StringComparison.OrdinalIgnoreCase)
134         Dim LQuery = (From item In source Where String.Equals(item.Key, Value, Method) Select item).ToArray
135         Return LQuery
136     End Function
137
138     ''' <summary>
139     ''' 这个函数假设参数<paramref name="source"/>之中是有重复的对象,则可以使用uniqueID数据提取出一个集合
140     ''' </summary>
141     ''' <typeparam name="T"></typeparam>
142     ''' <param name="source"></param>
143     ''' <param name="uniqueId"></param>
144     ''' <param name="strict">是否大小写敏感,默认大小写敏感</param>
145     ''' <returns></returns>
146     <Extension> Public Function Takes(Of T As INamedValue)(source As IEnumerable(Of T), uniqueId As StringOptional strict As Boolean = TrueAs T()
147         If source Is Nothing Then
148             Return New T() {}
149         End If
150
151         If strict Then
152             Dim table As Dictionary(Of String, T()) = source _
153                 .GroupBy(Function(o) o.Key) _
154                 .ToDictionary(Function(k) k.Key,
155                               Function(g) g.ToArray)
156
157             If table.ContainsKey(uniqueId) Then
158                 Return table(uniqueId)
159             Else
160                 Return {}
161             End If
162         Else
163             Return LinqAPI.Exec(Of T) _
164  _
165                 () <= From x As T
166                       In source
167                       Where String.Equals(x.Key, uniqueId, StringComparison.OrdinalIgnoreCase)
168                       Select x
169         End If
170     End Function
171
172     ''' <summary>
173     ''' 按照uniqueId列表来筛选出目标集合,这个函数是使用字典来进行查询操作的,故而效率会比较高
174     ''' </summary>
175     ''' <typeparam name="T"></typeparam>
176     ''' <param name="list">The list of ID value for <see cref="INamedValue.Key"/></param>
177     ''' <param name="source"></param>
178     ''' <returns></returns>
179     ''' <remarks></remarks>
180     <Extension> Public Function Takes(Of T As INamedValue)(list As IEnumerable(Of String), source As IEnumerable(Of T)) As T()
181         Dim table As Dictionary(Of T) = source.ToDictionary
182         Dim LQuery As T() = LinqAPI.Exec(Of T) _
183  _
184             () <= From sId As String
185                   In list
186                   Where table.ContainsKey(sId)
187                   Select table(sId)
188
189         Return LQuery
190     End Function
191
192     ''' <summary>
193     ''' 使用<paramref name="uniqueId"/>唯一标识符从集合之中取出一个目标对象。
194     ''' 小集合推荐使用这个函数,但是对于大型集合或者需要查询的次数非常多的话,则推荐使用字典操作来提升性能
195     ''' 请注意这个函数会完全匹配字符串的,即大小写敏感
196     ''' </summary>
197     ''' <typeparam name="T"></typeparam>
198     ''' <param name="source"></param>
199     ''' <param name="uniqueId"></param>
200     ''' <returns></returns>
201     <Extension> Public Function Take(Of T As INamedValue)(source As IEnumerable(Of T), uniqueId As StringOptional strict As Boolean = TrueAs T
202         Dim level As StringComparison = If(strict, StringComparison.Ordinal, StringComparison.OrdinalIgnoreCase)
203         Dim LQuery As T = LinqAPI.DefaultFirst(Of T) _
204  _
205             () <= From o As T
206                   In source
207                   Where String.Equals(uniqueId, o.Key, comparisonType:=level)
208                   Select o
209
210         Return LQuery
211     End Function
212
213     <Extension> Public Function ToEntryDictionary(Of T As IReadOnlyId)(source As IEnumerable(Of T)) As Dictionary(Of String, T)
214         Return source.ToDictionary(Function(item As T) item.Identity)
215     End Function
216
217     <Extension> Public Function GetItem(Of T As IReadOnlyId)(source As IEnumerable(Of T), uniqueId As StringOptional caseSensitive As Boolean = TrueAs T
218         Dim method As StringComparison = If(caseSensitive, StringComparison.Ordinal, StringComparison.OrdinalIgnoreCase)
219         Dim LQuery = LinqAPI.DefaultFirst(Of T) _
220  _
221             () <= From itemObj As T
222                   In source
223                   Where String.Equals(itemObj.Identity, uniqueId, method)
224                   Select itemObj
225
226         Return LQuery
227     End Function
228
229     ''' <summary>
230     ''' 
231     ''' </summary>
232     ''' <typeparam name="T"></typeparam>
233     ''' <param name="source"></param>
234     ''' <param name="distinct">
235     ''' True: 这个参数会去处重复项
236     ''' </param>
237     ''' <returns></returns>
238     <Extension> Public Function ToDictionary(Of T As INamedValue)(source As IEnumerable(Of T), distinct As BooleanAs Dictionary(Of T)
239         If Not distinct Then
240             Return source.ToDictionary
241         End If
242
243         Dim table As New Dictionary(Of T)
244         Dim duplicates As New List(Of String)
245
246         For Each x As T In source
247             If Not table.ContainsKey(x.Key) Then
248                 Call table.Add(x.Key, x)
249             Else
250                 duplicates += x.Key
251             End If
252         Next
253
254         If duplicates.Count > 0 Then
255             Call $"Dictionary table build complete, but there is dulplicated keys: {duplicates.GetJson}...".Warning
256         End If
257
258         Return table
259     End Function
260 End Module