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