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