1 #Region "Microsoft.VisualBasic::36430ceb520384fb21618375b295194d, Microsoft.VisualBasic.Core\Extensions\Collection\ListExtensions.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 ListExtensions
35     
36     '     Function: __reversedTake, AppendAfter, AsHashList, AsHashSet, AsList
37     '               AsLoop, HasKey, Indexing, rand, Random
38     '               ReorderByKeys, Takes, (+2 OverloadsToList, TopMostFrequent
39     
40     '     SubDoEach, ForEach, Swap
41     
42     ' /********************************************************************************/
43
44 #End Region
45
46 Imports System.Runtime.CompilerServices
47 Imports Microsoft.VisualBasic.CommandLine.Reflection
48 Imports Microsoft.VisualBasic.ComponentModel
49 Imports Microsoft.VisualBasic.ComponentModel.Collection
50 Imports Microsoft.VisualBasic.ComponentModel.DataStructures
51 Imports Microsoft.VisualBasic.Language
52 Imports Microsoft.VisualBasic.Linq
53
54 ''' <summary>
55 ''' Initializes a new instance of the <see cref="List"/>`1 class that
56 ''' contains elements copied from the specified collection and has sufficient capacity
57 ''' to accommodate the number of elements copied.
58 ''' </summary>
59 Public Module ListExtensions
60
61     ''' <summary>
62     ''' 将<paramref name="join"/>加入到<paramref name="list"/>序列后面
63     ''' </summary>
64     ''' <typeparam name="T"></typeparam>
65     ''' <param name="join"></param>
66     ''' <param name="list"></param>
67     ''' <returns></returns>
68     <Extension>
69     Public Iterator Function AppendAfter(Of T)(join As IEnumerable(Of T), list As IEnumerable(Of T)) As IEnumerable(Of T)
70         For Each x In list.SafeQuery
71             Yield x
72         Next
73         For Each x In join.SafeQuery
74             Yield x
75         Next
76     End Function
77
78     ''' <summary>
79     ''' 查找出序列之中最频繁出现的对象(这个函数会自动跳过空值)
80     ''' </summary>
81     ''' <typeparam name="T"></typeparam>
82     ''' <param name="list"></param>
83     ''' <returns></returns>
84     <MethodImpl(MethodImplOptions.AggressiveInlining)>
85     <Extension>
86     Public Function TopMostFrequent(Of T)(list As IEnumerable(Of T), Optional equals As IEqualityComparer(Of T) = NothingAs T
87         ' 因为可能会碰到list是空的情况,所以在这里需要使用FirstOrDefault
88         If equals Is Nothing Then
89             Return list _
90                 .SafeQuery _
91                 .Where(Function(x) Not x Is Nothing) _
92                 .GroupBy(Function(x) x) _
93                 .OrderByDescending(Function(g) g.Count) _
94                 .FirstOrDefault _
95                 .SafeQuery _
96                 .FirstOrDefault
97         Else
98             Return list _
99                 .SafeQuery _
100                 .Where(Function(x) Not x Is Nothing) _
101                 .GroupBy(Function(x) x, equals) _
102                 .OrderByDescending(Function(g) g.Count) _
103                 .FirstOrDefault _
104                 .SafeQuery _
105                 .FirstOrDefault
106         End If
107     End Function
108
109     ''' <summary>
110     ''' ForEach拓展的简化版本
111     ''' </summary>
112     ''' <typeparam name="T"></typeparam>
113     ''' <param name="collection"></param>
114     ''' <param name="[do]"></param>
115     <Extension> Public Sub DoEach(Of T)(collection As IEnumerable(Of T), [do] As Action(Of T))
116         For Each x As T In collection.SafeQuery
117             Call [do](x)
118         Next
119     End Sub
120
121     Private Function rand(min%, max%) As Integer
122         Static rnd As New Random
123         SyncLock rnd
124             Return rnd.Next(min, max)
125         End SyncLock
126     End Function
127
128     ''' <summary>
129     ''' 返回数组集合之中的一个随机位置的元素
130     ''' </summary>
131     ''' <typeparam name="T"></typeparam>
132     ''' <param name="v"></param>
133     ''' <returns></returns>
134     <Extension> Public Function Random(Of T)(v As T()) As T
135         Dim l% = rand(0, v.Length)
136         Return v(l)
137     End Function
138
139     ''' <summary>
140     ''' 根据对象的键名来进行重排序,请注意,要确保对象<paramref name="getKey"/>能够从泛型对象之中获取得到唯一的键名
141     ''' </summary>
142     ''' <typeparam name="T"></typeparam>
143     ''' <param name="list"></param>
144     ''' <param name="getKey"></param>
145     ''' <param name="customOrder">可能会出现大小写不对的情况?</param>
146     ''' <returns></returns>
147     <Extension>
148     Public Function ReorderByKeys(Of T)(list As IEnumerable(Of T), getKey As Func(Of T, String), customOrder$()) As List(Of T)
149         Dim ls As List(Of T) = list.AsList
150         Dim list2 As New List(Of T)
151         Dim internalGet_geneObj =
152             Function(id As String)
153                 Dim query = From x
154                             In ls.AsParallel
155                             Let key As String = getKey(x)
156                             Where key.TextEquals(id) OrElse
157                                 InStr(key, id, CompareMethod.Text) > 0 ' 假若是对基因组进行排序,可能getkey函数只获取得到的是编号,而customOrder之中还会包含有全称,所以用InStr判断一下?
158                             Select x '                 Return query.FirstOrDefault
159             End Function
160
161         For Each ID As String In customOrder
162             Dim selectedItem As T = internalGet_geneObj(ID)
163
164             If Not selectedItem Is Nothing Then ' 由于是倒序的,故而将对象移动到最后一个元素即可
165                 Call list2.Add(selectedItem)
166                 Call ls.Remove(selectedItem)
167             End If
168         Next
169
170         Call list2.AddRange(ls) ' 添加剩余的没有在customOrder之中找到的数据
171
172         Return list2
173     End Function
174
175     ''' <summary>
176     ''' Take elements by <paramref name="index"/> list. 
177     ''' </summary>
178     ''' <typeparam name="T"></typeparam>
179     ''' <param name="source"></param>
180     ''' <param name="index">所要获取的目标对象的下表的集合</param>
181     ''' <param name="reversed">是否为反向选择,即返回所有不在目标index集合之中的元素列表</param>
182     ''' <param name="OffSet">当进行反选的时候,本参数将不会起作用</param>
183     ''' <returns></returns>
184     ''' <remarks>
185     ''' ###### 2018-3-30 函数经过测试没有问题
186     ''' </remarks>
187     <ExportAPI("takes")>
188     <Extension> Public Function Takes(Of T)(source As IEnumerable(Of T),
189                                             index%(),
190                                             Optional offSet% = 0,
191                                             Optional reversed As Boolean = FalseAs T()
192         If reversed Then
193             Return source.__reversedTake(index)
194         End If
195
196         Dim result As T() = New T(index.Length - 1) {}
197         Dim indices As Index(Of Integer) = index _
198             .Select(Function(oi) oi + offSet) _
199             .Indexing
200
201         For Each x As SeqValue(Of T) In source.SeqIterator
202             ' 在这里得到的是x的index在indexs参数之中的索引位置
203             Dim i% = indices.IndexOf(x:=x.i)
204
205             ' 当前的原始的下表位于indexs参数值中,则第i个indexs元素所指向的source的元素
206             ' 就是x, 将其放入对应的结果列表之中
207             If i > -1 Then
208                 result(i) = x.value
209             End If
210         Next
211
212         Return result
213     End Function
214
215     ''' <summary>
216     ''' 反选,即将所有不出现在<paramref name="indexs"></paramref>之中的元素都选取出来
217     ''' </summary>
218     ''' <typeparam name="T"></typeparam>
219     ''' <param name="collection"></param>
220     ''' <param name="indexs"></param>
221     ''' <returns></returns>
222     ''' <remarks></remarks>
223     ''' 
224     <Extension>
225     Private Function __reversedTake(Of T)(collection As IEnumerable(Of T), indexs As Integer()) As T()
226         Dim indices As New Index(Of Integer)(indexs)
227         Dim out As New List(Of T)
228
229         For Each x As SeqValue(Of T) In collection.SeqIterator
230             If indices.IndexOf(x:=x.i) = -1 Then  ' 不存在于顶点的列表之中,即符合反选的条件,则添加进入结果之中
231                 out += x.value
232             End If
233         Next
234
235         Return out
236     End Function
237
238     <MethodImpl(MethodImplOptions.AggressiveInlining)>
239     <Extension>
240     Public Function Indexing(Of T)(source As IEnumerable(Of T)) As Index(Of T)
241         Return New Index(Of T)(source)
242     End Function
243
244     <Extension>
245     Public Sub Swap(Of T)(ByRef l As System.Collections.Generic.List(Of T), i%, j%)
246         Dim tmp = l(i)
247         l(i) = l(j)
248         l(j) = tmp
249     End Sub
250
251     <Extension>
252     Public Sub ForEach(Of T)(source As IEnumerable(Of T), action As Action(Of T, Integer))
253         For Each x As SeqValue(Of T) In source.SeqIterator
254             Call action(x.value, x.i)
255         Next
256     End Sub
257
258     ''' <summary>
259     ''' Initializes a new instance of the <see cref="List"/>`1 class that
260     ''' contains elements copied from the specified collection and has sufficient capacity
261     ''' to accommodate the number of elements copied.
262     ''' </summary>
263     ''' <param name="source">The collection whose elements are copied to the new list.</param>
264     <Extension> Public Function ToList(Of T, TOut)(
265                                   source As IEnumerable(Of T),
266                                  [CType] As Func(Of T, TOut),
267                        Optional parallel As Boolean = FalseAs List(Of TOut)
268
269         If source Is Nothing Then
270             Return New List(Of TOut)
271         End If
272
273         Dim result As List(Of TOut)
274
275         If parallel Then
276             result = (From x As T In source.AsParallel Select [CType](x)).AsList
277         Else
278             result = (From x As T In source Select [CType](x)).AsList
279         End If
280
281         Return result
282     End Function
283
284     <MethodImpl(MethodImplOptions.AggressiveInlining)>
285     <Extension>
286     Public Function AsLoop(Of T)(src As IEnumerable(Of T)) As LoopArray(Of T)
287         Return New LoopArray(Of T)(src)
288     End Function
289
290     ''' <summary>
291     ''' Initializes a new instance of the <see cref="List(Of T)"/> class that
292     ''' contains elements copied from the specified collection and has sufficient capacity
293     ''' to accommodate the number of elements copied.
294     ''' </summary>
295     ''' <param name="source">
296     ''' The collection whose elements are copied to the new list.
297     ''' </param>
298     <Extension> Public Function AsList(Of T)(source As IEnumerable(Of T)) As List(Of T)
299         ' 如果source集合是空值的话,不会抛错
300         Return New List(Of T)(source)
301     End Function
302
303     ''' <summary>
304     ''' Function name alias of the function <see cref="Hashtable.ContainsKey(Object)"/>
305     ''' </summary>
306     ''' <param name="hashtable"></param>
307     ''' <param name="key"></param>
308     ''' <returns></returns>
309     <MethodImpl(MethodImplOptions.AggressiveInlining)>
310     <Extension>
311     Public Function HasKey(hashtable As Hashtable, key As ObjectAs Boolean
312         Return hashtable.ContainsKey(key)
313     End Function
314
315     ''' <summary>
316     ''' Just using for the element index in a large collection
317     ''' </summary>
318     ''' <typeparam name="T"></typeparam>
319     ''' <param name="collection">
320     ''' If the element in this collection have some duplicated member, then only the first element will be keeped.
321     ''' </param>
322     ''' <returns></returns>
323     <Extension>
324     Public Function AsHashSet(Of T)(collection As IEnumerable(Of T)) As Hashtable
325         Dim table As New Hashtable
326
327         For Each x As SeqValue(Of T) In collection.SeqIterator
328             With x
329                 If Not table.ContainsKey(.value) Then
330                     Call table.Add(.value, .i)
331                 End If
332             End With
333         Next
334
335         Return table
336     End Function
337
338     ''' <summary>
339     ''' <see cref="HashList(Of T)"/>
340     ''' </summary>
341     ''' <typeparam name="T"></typeparam>
342     ''' <param name="source"></param>
343     ''' <returns></returns>
344     <MethodImpl(MethodImplOptions.AggressiveInlining)>
345     <Extension>
346     Public Function AsHashList(Of T As IAddressOf)(source As IEnumerable(Of T)) As HashList(Of T)
347         Return New HashList(Of T)(source)
348     End Function
349
350     ''' <summary>
351     ''' Initializes a new instance of the <see cref="List"/> class that
352     ''' contains elements copied from the specified collection and has sufficient capacity
353     ''' to accommodate the number of elements copied.
354     ''' </summary>
355     ''' <param name="linq">The collection whose elements are copied to the new list.</param>
356     <Extension> Public Function ToList(Of T)(linq As ParallelQuery(Of T)) As List(Of T)
357         Return New List(Of T)(linq)
358     End Function
359 End Module