1 #Region "Microsoft.VisualBasic::62f3cb3f47ab7f039f7f466914719d0a, Microsoft.VisualBasic.Core\Extensions\Collection\Linq\Linq.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 Extensions
35     
36     '         Function: CopyVector, DATA, DefaultFirst, FirstOrDefault, IteratesALL
37     '                   (+2 Overloads) JoinIterates, LastOrDefault, MaxInd, Populate, (+2 Overloads) Read
38     '                   RemoveLeft, (+2 Overloads) Removes, Repeats, SafeQuery, (+2 Overloads) SeqIterator
39     '                   (+4 Overloads) Sequence, (+4 OverloadsToArray, ToVector, TryCatch
40     
41     
42     ' /********************************************************************************/
43
44 #End Region
45
46 Imports System.Runtime.CompilerServices
47 Imports Microsoft.VisualBasic.CommandLine.Reflection
48 Imports Microsoft.VisualBasic.Emit.Delegates
49 Imports Microsoft.VisualBasic.Language
50 Imports Microsoft.VisualBasic.Scripting.MetaData
51
52 Namespace Linq
53
54     ''' <summary>
55     ''' Linq Helpers.(为了方便编写Linq代码而构建的一个拓展模块)
56     ''' </summary>
57     <Package("LINQ", Category:=APICategories.UtilityTools)>
58     <Extension>
59     Public Module Extensions
60
61         <Extension>
62         Public Function Populate(Of T)(source As IEnumerable(Of T), parallel As BooleanOptional degreeOfParallelism% = -1) As IEnumerable(Of T)
63             If parallel Then
64                 If degreeOfParallelism > 1 Then
65                     Return source.AsParallel.WithDegreeOfParallelism(degreeOfParallelism)
66                 Else
67                     Return source.AsParallel
68                 End If
69             Else
70                 Return source
71             End If
72         End Function
73
74         Public Function DATA(Of T)(src As IEnumerable(Of T)) As DataValue(Of T)
75             Return New DataValue(Of T)(src)
76         End Function
77
78         <Extension>
79         Public Function ToArray(Of T)(source As IEnumerable(Of Object)) As T()
80             If source Is Nothing Then
81                 Return New T() {}
82             Else
83                 Return (From x As Object In source Select DirectCast(x, T)).ToArray
84             End If
85         End Function
86
87         ''' <summary>
88         ''' A query proxy function makes your linq not so easily crashed due to the 
89         ''' unexpected null reference collection as linq source.
90         ''' </summary>
91         ''' <typeparam name="T"></typeparam>
92         ''' <param name="source"></param>
93         ''' <returns></returns>
94         <Extension>
95         Public Function SafeQuery(Of T)(source As IEnumerable(Of T)) As IEnumerable(Of T)
96             If Not source Is Nothing Then
97                 Return source
98             Else
99                 Return {}
100             End If
101         End Function
102
103         ''' <summary>
104         ''' Gets the max element its index in the collection
105         ''' </summary>
106         ''' <typeparam name="T"></typeparam>
107         ''' <param name="source"></param>
108         ''' <returns></returns>
109         <Extension> Public Function MaxInd(Of T As IComparable)(source As IEnumerable(Of T)) As Integer
110             Dim i As Integer = 0
111             Dim m As T
112             Dim mi As Integer
113
114             For Each x As T In source
115                 If x.CompareTo(m) > 0 Then
116                     m = x
117                     mi = i
118                 End If
119
120                 i += 1
121             Next
122
123             Return mi
124         End Function
125
126         ''' <summary>
127         '''
128         ''' </summary>
129         ''' <typeparam name="T"></typeparam>
130         ''' <param name="source"></param>
131         ''' <param name="match">符合这个条件的所有的元素都将会被移除</param>
132         ''' <returns></returns>
133         <Extension> Public Function Removes(Of T)(source As IEnumerable(Of T), match As Func(Of T, Boolean), Optional parallel As Boolean = FalseAs T()
134             Dim LQuery As T()
135             If parallel Then
136                 LQuery = (From x In source.AsParallel Where Not match(x) Select x).ToArray
137             Else
138                 LQuery = (From x In source Where Not match(x) Select x).ToArray
139             End If
140             Return LQuery
141         End Function
142
143         <Extension> Public Function Removes(Of T)(lst As List(Of T), match As Func(Of T, Boolean)) As List(Of T)
144             If lst.IsNullOrEmpty Then
145                 Return New List(Of T)
146             Else
147                 For Each x In lst.ToArray
148                     If match(x) Then
149                         Call lst.Remove(x)
150                     End If
151                 Next
152
153                 Return lst
154             End If
155         End Function
156
157         Public Function TryCatch(Of T)(source As Func(Of T),
158                                        msg$,
159                                        Optional throwEx As Boolean = True,
160                                        Optional ByRef exception As Exception = NothingAs T
161             Try
162                 Return source()
163             Catch ex As Exception
164                 ex = New Exception(msg, ex)
165                 exception = ex
166
167                 Call App.LogException(ex, source.ToString)
168
169                 If throwEx Then
170                     Throw ex
171                 Else
172                     Return Nothing
173                 End If
174             End Try
175         End Function
176
177         ''' <summary>
178         ''' Iterates all of the elements in a two dimension collection as the data source 
179         ''' for the linq expression or ForEach statement.
180         ''' (适用于二维的集合做为linq的数据源,不像<see cref="Unlist"/>是进行转换,
181         ''' 这个是返回迭代器的,推荐使用这个函数)
182         ''' </summary>
183         ''' <typeparam name="T"></typeparam>
184         ''' <param name="source"></param>
185         ''' <returns></returns>
186         <Extension> Public Iterator Function IteratesALL(Of T)(source As IEnumerable(Of IEnumerable(Of T))) As IEnumerable(Of T)
187             For Each line As IEnumerable(Of T) In source
188                 If Not line Is Nothing Then
189                     Using iterator = line.GetEnumerator
190                         Do While iterator.MoveNext
191                             Yield iterator.Current
192                         Loop
193                     End Using
194                 End If
195             Next
196         End Function
197
198         ''' <summary>
199         ''' First, iterate populates the elements in collection <paramref name="a"/>, 
200         ''' and then populate out all of the elements on collection <paramref name="b"/>
201         ''' </summary>
202         ''' <typeparam name="T"></typeparam>
203         ''' <param name="a">Object collection</param>
204         ''' <param name="b">Another object collection.</param>
205         ''' <returns></returns>
206         <Extension>
207         Public Iterator Function JoinIterates(Of T)(a As IEnumerable(Of T), b As IEnumerable(Of T)) As IEnumerable(Of T)
208             If Not a Is Nothing Then
209                 For Each x As T In a
210                     Yield x
211                 Next
212             End If
213             If Not b Is Nothing Then
214                 For Each x As T In b
215                     Yield x
216                 Next
217             End If
218         End Function
219
220         <Extension>
221         Public Iterator Function JoinIterates(Of T)(a As IEnumerable(Of T), b As T) As IEnumerable(Of T)
222             If Not a Is Nothing Then
223                 For Each x As T In a
224                     Yield x
225                 Next
226             End If
227
228             Yield b
229         End Function
230
231         ''' <summary>
232         ''' Removes the specific key in the dicitonary and returns the last content.
233         ''' (删除指定的键之后返回剩下的数据)
234         ''' </summary>
235         ''' <typeparam name="TKey"></typeparam>
236         ''' <typeparam name="TValue"></typeparam>
237         ''' <param name="source"></param>
238         ''' <param name="key"></param>
239         ''' <returns></returns>
240         <Extension>
241         Public Function RemoveLeft(Of TKey, TValue)(ByRef source As Dictionary(Of TKey, TValue), key As TKey) As Dictionary(Of TKey, TValue)
242             With source
243                 If .ContainsKey(key) Then
244                     Call .Remove(key)
245                 End If
246             End With
247
248             Return source
249         End Function
250
251         ''' <summary>
252         ''' Copy <paramref name="source"/> <paramref name="times"/> times to construct a new vector.
253         ''' </summary>
254         ''' <typeparam name="T"></typeparam>
255         ''' <param name="source"></param>
256         ''' <param name="times"></param>
257         ''' <returns>An array consist of source with n elements.</returns>
258         ''' 
259         <MethodImpl(MethodImplOptions.AggressiveInlining)>
260         <Extension> Public Function Repeats(Of T)(source As T, times%) As T()
261             Return times.Sequence.Select(Function(x) source).ToArray
262         End Function
263
264         ''' <summary>
265         ''' 
266         ''' </summary>
267         ''' <typeparam name="T"></typeparam>
268         ''' <param name="n"></param>
269         ''' <param name="source">The object factory</param>
270         ''' <returns></returns>
271         <MethodImpl(MethodImplOptions.AggressiveInlining)>
272         <Extension>
273         Public Function CopyVector(Of T)(n As Integer, source As Func(Of T)) As T()
274             Return n.Sequence.Select(Function(x) source()).ToArray
275         End Function
276
277         <Extension> Public Function Read(Of T)(array As T(), ByRef i As IntegerByRef out As T) As T
278             out = array(i)
279             i += 1
280             Return out
281         End Function
282
283         ''' <summary>
284         ''' Read source at element position <paramref name="i"/> and returns its value, 
285         ''' and then this function makes position <paramref name="i"/> offset +1
286         ''' </summary>
287         ''' <typeparam name="T"></typeparam>
288         ''' <param name="array"></param>
289         ''' <param name="i"></param>
290         ''' <returns></returns>
291         <Extension> Public Function Read(Of T)(array As T(), ByRef i As IntegerAs T
292             Dim out As T = array(i)
293             i += 1
294             Return out
295         End Function
296
297         ''' <summary>
298         ''' 产生指定数目的一个递增序列(用于生成序列的输入参数<paramref name="n"/>数值就是生成的数组的元素的个数)
299         ''' </summary>
300         ''' <param name="n">大于或者等于0的一个数,当小于0的时候会出错</param>
301         ''' <returns></returns>
302         ''' <remarks></remarks>
303         '''
304         <ExportAPI("Sequence")>
305         <Extension> Public Iterator Function Sequence(n As IntegerAs IEnumerable(Of Integer)
306             If n < 0 Then
307                 Dim ex As String = $"n:={n} is not a valid index generator value for sequence!"
308                 Throw New Exception(ex)
309             End If
310
311             For i As Integer = 0 To n - 1
312                 Yield i
313             Next
314         End Function
315
316         ''' <summary>
317         ''' ``0,1,2,3,...<paramref name="n"/>``
318         ''' </summary>
319         ''' <param name="n"></param>
320         ''' <param name="offset"></param>
321         ''' <returns></returns>
322         <Extension>
323         Public Iterator Function SeqIterator(n As IntegerOptional offset As Integer = 0) As IEnumerable(Of Integer)
324             If n < 0 Then
325                 Dim ex As String = $"n:={n} is not a valid index generator value for sequence!"
326                 Throw New Exception(ex)
327             End If
328
329             For i As Integer = 0 To n - 1
330                 Yield (i + offset)
331             Next
332         End Function
333
334         ''' <summary>
335         ''' 假若数量已经超过了数组的容量,则需要使用这个函数来产生序列
336         ''' </summary>
337         ''' <param name="n"></param>
338         ''' <param name="offset"></param>
339         ''' <returns></returns>
340         <Extension>
341         Public Iterator Function SeqIterator(n As LongOptional offset As Integer = 0) As IEnumerable(Of Long)
342             If n < 0 Then
343                 Dim ex As String = $"n:={n} is not a valid index generator value for sequence!"
344                 Throw New Exception(ex)
345             End If
346
347             For i As Long = 0 To n - 1
348                 Yield (i + offset)
349             Next
350         End Function
351
352         <Extension, ExportAPI("Sequence")>
353         Public Function Sequence(n As Integer, offset As IntegerAs Integer()
354             Dim array As Integer() = n.Sequence
355
356             For i As Integer = 0 To array.Length - 1
357                 array(i) = array(i) + offset
358             Next
359
360             Return array
361         End Function
362
363         ''' <summary>
364         ''' 产生指定数目的一个递增序列(所生成序列的数值就是生成的数组的元素的个数)
365         ''' </summary>
366         ''' <param name="n"></param>
367         ''' <returns></returns>
368         ''' <remarks></remarks>
369         '''
370         <ExportAPI("Sequence")>
371         <Extension> Public Function Sequence(n As LongAs Long()
372             Dim List As Long() = New Long(n - 1) {}
373             For i As Integer = 0 To n - 1
374                 List(i) = i
375             Next
376             Return List
377         End Function
378
379         ''' <summary>
380         ''' 产生指定数目的一个递增序列(所生成序列的数值就是生成的数组的元素的个数)
381         ''' </summary>
382         ''' <param name="n"></param>
383         ''' <returns></returns>
384         ''' <remarks></remarks>
385         '''
386         <ExportAPI("Sequence")>
387         <Extension> Public Function Sequence(n As UIntegerAs Integer()
388             Dim List(n - 1) As Integer
389             For i As Integer = 0 To n - 1
390                 List(i) = i
391             Next
392             Return List
393         End Function
394
395         ''' <summary>
396         ''' (所生成序列的数值就是生成的数组的元素的个数)
397         ''' </summary>
398         ''' <typeparam name="T"></typeparam>
399         ''' <param name="len"></param>
400         ''' <param name="elementAt"></param>
401         ''' <returns></returns>
402         <MethodImpl(MethodImplOptions.AggressiveInlining)>
403         <Extension> Public Function ToArray(Of T)(len As Integer, elementAt As Func(Of Integer, T)) As T()
404             Return len _
405                 .Sequence _
406                 .Select(elementAt) _
407                 .ToArray
408         End Function
409
410         <MethodImpl(MethodImplOptions.AggressiveInlining)>
411         <Extension> Public Function ToArray(Of T)(len&, elementAt As Func(Of Long, T)) As T()
412             Return len _
413                 .Sequence _
414                 .Select(elementAt) _
415                 .ToArray
416         End Function
417
418         ''' <summary>
419         ''' Returns the first element of a sequence, or a default value if the sequence contains no elements.
420         ''' </summary>
421         ''' <typeparam name="TSource">The type of the elements of source.</typeparam>
422         ''' <param name="source">The System.Collections.Generic.IEnumerable`1 to return the first element of.</param>
423         ''' <param name="[default]">
424         ''' If the sequence is nothing or contains no elements, then this default value will be returned.
425         ''' </param>
426         ''' <returns>default(TSource) if source is empty; otherwise, the first element in source.</returns>
427         <Extension> Public Function FirstOrDefault(Of TSource)(source As IEnumerable(Of TSource), [default] As TSource) As TSource
428             Dim value As TSource = source.FirstOrDefault
429
430             If value Is Nothing Then
431                 Return [default]
432             Else
433                 Return value
434             End If
435         End Function
436
437         <Extension>
438         Public Function LastOrDefault(Of T)(source As IEnumerable(Of T), [default] As T) As T
439             Dim value As T = source.LastOrDefault
440
441             If value Is Nothing Then
442                 Return [default]
443             Else
444                 Return value
445             End If
446         End Function
447
448         ''' <summary>
449         ''' Returns the first element of a sequence, or a default value if the sequence contains no elements.
450         ''' </summary>
451         ''' <typeparam name="T">The type of the elements of source.</typeparam>
452         ''' <param name="source">The System.Collections.Generic.IEnumerable`1 to return the first element of.</param>
453         ''' <param name="[default]">
454         ''' If the sequence is nothing or contains no elements, then this default value will be returned.
455         ''' </param>
456         ''' <returns>default(TSource) if source is empty; otherwise, the first element in source.</returns>
457         <Extension> Public Function DefaultFirst(Of T)(source As IEnumerable(Of T), Optional [default] As T = NothingAs T
458             If source Is Nothing Then
459                 Return [default]
460             Else
461                 Return source.FirstOrDefault
462             End If
463         End Function
464
465         ''' <summary>
466         ''' Convert the iterator source <see cref="IEnumerable"/> to an object array.
467         ''' </summary>
468         ''' <param name="source"></param>
469         ''' <returns></returns>
470         <MethodImpl(MethodImplOptions.AggressiveInlining)>
471         <Extension>
472         Public Function ToVector(source As IEnumerable) As Object()
473             If source Is Nothing Then
474                 Return {}
475             Else
476                 Return (From x As Object In source Select x).ToArray
477             End If
478         End Function
479
480         ''' <summary>
481         ''' Convert the iterator source <see cref="IEnumerable"/> to a specific type array.
482         ''' </summary>
483         ''' <typeparam name="T"></typeparam>
484         ''' <param name="source"></param>
485         ''' <returns></returns>
486         <Extension>
487         Public Function ToArray(Of T)(source As IEnumerable) As T()
488             Return ToVector(source) _
489                 .Select(Function(x) If(x Is NothingNothingDirectCast(x, T))) _
490                 .ToArray
491         End Function
492     End Module
493 End Namespace