1 | #Region "Microsoft.VisualBasic::fd9fd9a6014fb2dcdf7f43388f6142f4, Microsoft.VisualBasic.Core\ComponentModel\Ranges\Extensions.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: (+2 Overloads) GetScaler, (+2 Overloads) RangeTransform, SymmetricalRange, Union |
37 | ' |
38 | ' Sub: Parser |
39 | ' |
40 | ' |
41 | ' /********************************************************************************/ |
42 | |
43 | #End Region |
44 | |
45 | Imports System.Runtime.CompilerServices |
46 | Imports System.Text.RegularExpressions |
47 | Imports Microsoft.VisualBasic.ComponentModel.Ranges.Model |
48 | Imports Microsoft.VisualBasic.Language |
49 | Imports Microsoft.VisualBasic.Linq |
50 | Imports Microsoft.VisualBasic.Scripting.Runtime |
51 | Imports r = System.Text.RegularExpressions.Regex |
52 | Imports sys = System.Math |
53 | |
54 | Namespace ComponentModel.Ranges |
55 | |
56 | Public Module Extensions |
57 | |
58 | ''' <summary> |
59 | ''' 对称的的范围,假若X为正数,那么其为max,而-x为min。假若x为负数,那么-x为max |
60 | ''' </summary> |
61 | ''' <param name="x#"></param> |
62 | ''' <returns></returns> |
63 | <Extension> |
64 | Public Function SymmetricalRange(x#) As DoubleRange |
65 | If x > 0 Then |
66 | Return {-x, x} |
67 | Else |
68 | Return {x, -x} |
69 | End If |
70 | End Function |
71 | |
72 | Const RegexpFloatRange$ = RegexpFloat & "\s*,\s*" & RegexpFloat |
73 | |
74 | ''' <summary> |
75 | ''' + ``min -> max`` |
76 | ''' + ``min—max`` |
77 | ''' + ``min~max`` |
78 | ''' + ``[min,max]`` |
79 | ''' + ``{min,max}`` |
80 | ''' + ``(min,max)`` |
81 | ''' + ``min,max`` |
82 | ''' </summary> |
83 | ''' <param name="exp$"></param> |
84 | ''' <param name="min#"></param> |
85 | ''' <param name="max#"></param> |
86 | <Extension> Public Sub Parser(exp$, ByRef min#, ByRef max#) |
87 | Dim t$() |
88 | Dim raw$ = exp |
89 | |
90 | If InStr(exp, "->") > 0 Then |
91 | t = Strings.Split(exp, "->") |
92 | ElseIf InStr(exp, "—") > 0 Then |
93 | ' 使用的是中文的分隔符 |
94 | t = Strings.Split(exp, "—") |
95 | ElseIf InStr(exp, "~") > 0 Then |
96 | t = Strings.Split(exp, "~") |
97 | ElseIf exp.IsPattern(RegexpDouble & "\s*[-]\s*" & RegexpDouble) Then |
98 | ' 使用的是英文的分隔符 |
99 | ' 因为可能会和负号弄混,所以在这里需要使用正则表达式来匹配出这个分隔符 |
100 | ' 因为是这种格式的range: dd-dd |
101 | ' 故而分隔符的pattern肯定是数字加连接符本身,将这个pattern匹配出来,然后利用这个pattern进行分割即可 |
102 | Dim del$ = r.Match(exp, "\d\s*[-]").Value |
103 | t = Strings.Split(exp, del) |
104 | ' 需要将存在于del的pattern之中的前面的数字的最后一个数值补回来 |
105 | t(0) = t(0) & del.Trim("-"c) |
106 | Else |
107 | exp = r _ |
108 | .Match(exp, RegexpFloatRange, RegexOptions.Singleline) _ |
109 | .Value |
110 | |
111 | If String.IsNullOrEmpty(exp) Then |
112 | exp = $"'{raw}' is not a valid expression format!" |
113 | Throw New FormatException(exp) |
114 | Else |
115 | t = exp.Split(","c) |
116 | End If |
117 | End If |
118 | |
119 | t = t _ |
120 | .Select(AddressOf Trim) _ |
121 | .ToArray |
122 | |
123 | min = Casting.ParseNumeric(t(Scan0)) |
124 | max = Casting.ParseNumeric(t(1)) |
125 | End Sub |
126 | |
127 | ''' <summary> |
128 | ''' 返回一个实数区间的范围百分比的生成函数:``[0-1]``之间 |
129 | ''' </summary> |
130 | ''' <param name="range"></param> |
131 | ''' <returns></returns> |
132 | <Extension> |
133 | Public Function GetScaler(range As DoubleRange) As Func(Of Double, Double) |
134 | Dim length# = range.Length |
135 | Dim min# = range.Min |
136 | |
137 | Return Function(x#) |
138 | Return (x - min) / length |
139 | End Function |
140 | End Function |
141 | |
142 | <Extension> |
143 | Public Function GetScaler(vector As IEnumerable(Of Double)) As Func(Of Double, Double) |
144 | With vector.ToArray |
145 | Return New DoubleRange(.Min, .Max).GetScaler |
146 | End With |
147 | End Function |
148 | |
149 | ''' <summary> |
150 | ''' 将目标区间内的任意实数全部转换为<paramref name="to"/>区间内的实数 |
151 | ''' </summary> |
152 | ''' <param name="from"></param> |
153 | ''' <param name="[to]"></param> |
154 | ''' <returns></returns> |
155 | <Extension> |
156 | Public Function RangeTransform(from As IEnumerable(Of Double), [to] As DoubleRange) As Double() |
157 | If from Is Nothing Then |
158 | Return {} |
159 | End If |
160 | |
161 | Dim vector#() = from.ToArray |
162 | Dim scale = New DoubleRange(vector).GetScaler |
163 | Dim percentages#() = vector.Select(scale).ToArray |
164 | Dim length# = [to].Length |
165 | Dim min# = [to].Min |
166 | Dim maps#() = percentages.Select(Function(x) x * length + min).ToArray |
167 | Return maps |
168 | End Function |
169 | |
170 | ''' <summary> |
171 | ''' 将目标区间内的任意实数全部转换为<paramref name="to"/>区间内的实数 |
172 | ''' </summary> |
173 | ''' <param name="from"></param> |
174 | ''' <param name="[to]"></param> |
175 | ''' <returns></returns> |
176 | ''' |
177 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
178 | <Extension> |
179 | Public Function RangeTransform(from As IEnumerable(Of Integer), [to] As IntRange) As Integer() |
180 | Return from _ |
181 | .Select(Function(x) CDbl(x)) _ |
182 | .RangeTransform(New DoubleRange([to])) _ |
183 | .Select(Function(x) CInt(x)) _ |
184 | .ToArray |
185 | End Function |
186 | |
187 | <Extension> |
188 | Public Function Union(fragments As IEnumerable(Of IntRange)) As IEnumerable(Of IntRange) |
189 | Dim unions As New List(Of IntRange) |
190 | |
191 | For Each f In fragments.OrderBy(Function(r) r.Min) |
192 | If unions = 0 Then |
193 | unions += New IntRange(f.Min, f.Max) |
194 | Else |
195 | Dim isUnion As Boolean = False |
196 | |
197 | For Each region In unions |
198 | If region.IsOverlapping(f) OrElse region.IsInside(f) Then |
199 | region.Min = sys.Min(region.Min, f.Min) |
200 | region.Max = sys.Max(region.Max, f.Max) |
201 | |
202 | isUnion = True |
203 | End If |
204 | Next |
205 | |
206 | If Not isUnion Then |
207 | unions += New IntRange(f.Min, f.Max) |
208 | End If |
209 | End If |
210 | Next |
211 | |
212 | Return unions |
213 | End Function |
214 | End Module |
215 | End Namespace |