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 Overloads) ToList, TopMostFrequent |
39 | ' |
40 | ' Sub: DoEach, 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) = Nothing) As 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 = False) As 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 = False) As 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 Object) As 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 |