1 #Region "Microsoft.VisualBasic::cf2a2d27c2045d7e705b0446b4cabfe0, Microsoft.VisualBasic.Core\Extensions\Collection\KeyValuePair.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 KeyValuePairExtensions
35
36 '     Function: (+3 Overloads) [Select], (+2 Overloads) Add, AsGroups, AsNamedValueTuples, AsNamedVector
37 '               AsTable, (+3 Overloads) ContainsKey, DictionaryData, (+2 OverloadsEnumerateTuples, EnumParser
38 '               FlatTable, (+2 OverloadsGetByKey, GroupByKey, HaveData, IGrouping
39 '               IsOneOfA, IterateNameCollections, IterateNameValues, IteratesAll, Join
40 '               KeyItem, (+2 Overloads) Keys, (+2 Overloads) NamedValues, (+2 Overloads) NameValueCollection, ParserDictionary
41 '               RemoveAndGet, ReverseMaps, Selects, (+2 OverloadsSubset, Takes
42 '               (+3 OverloadsToDictionary, Tsv, Tuple, (+2 Overloads) Values, XMLModel
43
44 '     Sub: SortByKey, SortByValue
45
46 ' /********************************************************************************/
47
48 #End Region
49
50 Imports System.Collections.Specialized
51 Imports System.Runtime.CompilerServices
52 Imports Microsoft.VisualBasic.CommandLine.Reflection
53 Imports Microsoft.VisualBasic.ComponentModel
54 Imports Microsoft.VisualBasic.ComponentModel.Collection
55 Imports Microsoft.VisualBasic.ComponentModel.Collection.Generic
56 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
57 Imports Microsoft.VisualBasic.Language
58 Imports Microsoft.VisualBasic.Linq
59 Imports Microsoft.VisualBasic.Serialization.JSON
60 Imports Microsoft.VisualBasic.Text
61 Imports Microsoft.VisualBasic.Text.Xml.Models
62 Imports r = System.Text.RegularExpressions.Regex
63
64 ''' <summary>
65 ''' KeyValue pair data related extensions API.
66 ''' </summary>
67 Public Module KeyValuePairExtensions
68
69     <Extension>
70     Public Iterator Function AsEnumerable(keys As NameObjectCollectionBase.KeysCollection) As IEnumerable(Of String)
71         If Not keys Is Nothing AndAlso keys.Count > 0 Then
72             For i As Integer = 0 To keys.Count - 1
73                 Yield keys.Item(i)
74             Next
75         End If
76     End Function
77
78     ''' <summary>
79     ''' Create a tuple for two elements
80     ''' </summary>
81     ''' <typeparam name="T1"></typeparam>
82     ''' <typeparam name="T2"></typeparam>
83     ''' <param name="a"></param>
84     ''' <param name="b"></param>
85     ''' <returns></returns>
86     <MethodImpl(MethodImplOptions.AggressiveInlining)>
87     <Extension>
88     Public Function Tuple(Of T1, T2)(a As T1, b As T2) As (T1, T2)
89         Return (a, b)
90     End Function
91
92     ''' <summary>
93     ''' 将目标键值对集合保存为一个``Tsv``文件
94     ''' </summary>
95     ''' <param name="table"></param>
96     ''' <param name="saveTo$"></param>
97     ''' <param name="encoding"></param>
98     ''' <returns></returns>
99     <Extension>
100     Public Function Tsv(table As Dictionary(Of StringString),
101                         saveTo$,
102                         Optional encoding As Encodings = Encodings.UTF8,
103                         Optional reversed As Boolean = FalseAs Boolean
104
105         Dim file$() = $"key{ASCII.TAB}map" +
106             table _
107             .Select(Function(map)
108                         If reversed Then
109                             Return $"{map.Value}{ASCII.TAB}{map.Key}"
110                         Else
111                             Return $"{map.Key}{ASCII.TAB}{map.Value}"
112                         End If
113                     End Function) _
114             .AsList
115         Return file.SaveTo(saveTo, encoding.CodePage)
116     End Function
117
118     ''' <summary>
119     ''' tuple set to dictionary table
120     ''' </summary>
121     ''' <typeparam name="K"></typeparam>
122     ''' <typeparam name="V"></typeparam>
123     ''' <param name="tuples"></param>
124     ''' <returns></returns>
125     <MethodImpl(MethodImplOptions.AggressiveInlining)>
126     <Extension>
127     Public Function AsTable(Of K, V)(tuples As IEnumerable(Of (K, V))) As Dictionary(Of K, V)
128         Return tuples.ToDictionary(Function(t) t.Item1, Function(t) t.Item2)
129     End Function
130
131     ''' <summary>
132     ''' Item selector by directly text equals match.
133     ''' </summary>
134     ''' <typeparam name="T"></typeparam>
135     ''' <param name="source"></param>
136     ''' <param name="key$"></param>
137     ''' <returns></returns>
138     <MethodImpl(MethodImplOptions.AggressiveInlining)>
139     <Extension>
140     Public Function KeyItem(Of T As INamedValue)(source As IEnumerable(Of T), key$) As T
141         Return source _
142             .Where(Function(i) i.Key = key) _
143             .FirstOrDefault
144     End Function
145
146     ''' <summary>
147     ''' Item selector by using regex expression.
148     ''' </summary>
149     ''' <typeparam name="T"></typeparam>
150     ''' <param name="source"></param>
151     ''' <param name="pattern$"></param>
152     ''' <returns></returns>
153     <MethodImpl(MethodImplOptions.AggressiveInlining)>
154     <Extension>
155     Public Function [Select](Of T As INamedValue)(source As IEnumerable(Of T), pattern$) As IEnumerable(Of T)
156         Return source.Where(Function(i) r.Match(i.Key, pattern, RegexICSng).Success)
157     End Function
158
159     ''' <summary>
160     ''' Target <paramref name="item"/> contains in <paramref name="define"/> list.
161     ''' </summary>
162     ''' <typeparam name="T"></typeparam>
163     ''' <param name="item"></param>
164     ''' <param name="define"></param>
165     ''' <returns></returns>
166     <MethodImpl(MethodImplOptions.AggressiveInlining)>
167     <Extension>
168     Public Function IsOneOfA(Of T)(item As T, define As Index(Of T)) As Boolean
169         Return define.IndexOf(item) > -1
170     End Function
171
172     ''' <summary>
173     ''' 函数会根据<see cref="keys"/>参数来做排序
174     ''' </summary>
175     ''' <typeparam name="T"></typeparam>
176     ''' <param name="table"></param>
177     ''' <param name="keys$"></param>
178     ''' <returns></returns>
179     ''' 
180     <MethodImpl(MethodImplOptions.AggressiveInlining)>
181     <Extension>
182     Public Function Subset(Of T)(table As Dictionary(Of String, T), keys$()) As Dictionary(Of String, T)
183         Return keys _
184             .Select(Function(key)
185                         Return (key:=key, Value:=table(key))
186                     End Function) _
187             .ToDictionary(Function(o) o.key,
188                           Function(o) o.Value)
189     End Function
190
191     <MethodImpl(MethodImplOptions.AggressiveInlining)>
192     <Extension>
193     Public Function Subset(Of K, V)(table As Dictionary(Of K, V), assert As Func(Of K, V, Boolean)) As Dictionary(Of K, V)
194         Return table _
195             .Where(Function(map) assert(map.Key, map.Value)) _
196             .ToDictionary(Function(map) map.Key,
197                           Function(map) map.Value)
198     End Function
199
200     ''' <summary>
201     ''' 按照给定的键名列表<paramref name="keys"/>将字典之中的对应的元素按照键名的顺序取出来
202     ''' </summary>
203     ''' <typeparam name="T"></typeparam>
204     ''' <param name="table"></param>
205     ''' <param name="keys"></param>
206     ''' <param name="nonExitsNULL">
207     ''' 如果这个参数为真,则对于不存在的键名,则使用
208     ''' </param>
209     ''' <returns></returns>
210     <MethodImpl(MethodImplOptions.AggressiveInlining)>
211     <Extension>
212     Public Function Takes(Of T)(table As IDictionary(Of String, T), keys As IEnumerable(Of String), Optional nonExitsNULL As Boolean = TrueAs T()
213         If nonExitsNULL Then
214             Return keys _
215                 .Select(Function(key)
216                             Return If(table.ContainsKey(key), table(key), Nothing)
217                         End Function) _
218                 .ToArray
219         Else
220             Return keys _
221                 .Select(Function(key) table(key)) _
222                 .ToArray
223         End If
224     End Function
225
226     <MethodImpl(MethodImplOptions.AggressiveInlining)>
227     <Extension>
228     Public Function XMLModel(data As IEnumerable(Of NamedValue(Of String))) As NamedValue()
229         Return data _
230             .Select(Function(n) New NamedValue With {.name = n.Name, .text = n.Value}) _
231             .ToArray
232     End Function
233
234     <Extension>
235     Public Iterator Function EnumerateTuples(Of T)(table As Dictionary(Of String, T)) As IEnumerable(Of (name As String, obj As T))
236         For Each entry In table
237             Yield (entry.Key, entry.Value)
238         Next
239     End Function
240
241     <Extension>
242     Public Iterator Function EnumerateTuples(Of K, V)(table As IEnumerable(Of KeyValuePair(Of K, V))) As IEnumerable(Of (tag As K, obj As V))
243         For Each entry In table
244             Yield (entry.Key, entry.Value)
245         Next
246     End Function
247
248     <Extension> Public Function AsNamedVector(Of T)(groups As IEnumerable(Of IGrouping(Of String, T))) As IEnumerable(Of NamedCollection(Of T))
249         Return groups.Select(Function(group)
250                                  Return New NamedCollection(Of T) With {
251                                     .Name = group.Key,
252                                     .Value = group.ToArray
253                                  }
254                              End Function)
255     End Function
256
257     <MethodImpl(MethodImplOptions.AggressiveInlining)>
258     <Extension>
259     Public Function AsNamedValueTuples(Of T)(tuples As IEnumerable(Of KeyValuePair(Of String, T))) As IEnumerable(Of NamedValue(Of T))
260         Return tuples.Select(Function(p) New NamedValue(Of T)(p.Key, p.Value))
261     End Function
262
263     <Extension>
264     Public Function AsGroups(Of T)(table As Dictionary(Of String, T())) As IEnumerable(Of NamedCollection(Of T))
265         Return table.Select(Function(item)
266                                 Return New NamedCollection(Of T) With {
267                                     .Name = item.Key,
268                                     .Value = item.Value
269                                 }
270                             End Function)
271     End Function
272
273     <MethodImpl(MethodImplOptions.AggressiveInlining)>
274     <Extension>
275     Public Function IGrouping(Of T)(source As IEnumerable(Of NamedCollection(Of T))) As IEnumerable(Of IGrouping(Of String, T))
276         Return source.Select(Function(x) DirectCast(x, IGrouping(Of String, T)))
277     End Function
278
279     ''' <summary>
280     ''' Removes the target key in the dictionary table, and then gets the removed value.
281     ''' (删除字典之中的指定的键值对,然后返回被删除的数据值)
282     ''' </summary>
283     ''' <typeparam name="K"></typeparam>
284     ''' <typeparam name="V"></typeparam>
285     ''' <param name="table"></param>
286     ''' <param name="key"></param>
287     ''' <returns>The value of the removed <paramref name="key"/></returns>
288     <Extension>
289     Public Function RemoveAndGet(Of K, V)(table As Dictionary(Of K, V), key As K) As V
290         Dim item As V = table(key)
291         Call table.Remove(key)
292         Return item
293     End Function
294
295     ''' <summary>
296     ''' Iterates all of the values in the <paramref name="source"/> collection data.
297     ''' </summary>
298     ''' <typeparam name="T"></typeparam>
299     ''' <param name="source"></param>
300     ''' <returns></returns>
301     <Extension>
302     Public Function IteratesAll(Of T As INamedValue)(source As IEnumerable(Of NamedCollection(Of T))) As T()
303         Return source.Select(Function(c) c.Value).IteratesALL.ToArray
304     End Function
305
306     ''' <summary>
307     ''' Groups source by <see cref="INamedValue.Key"/>
308     ''' </summary>
309     ''' <typeparam name="T"></typeparam>
310     ''' <param name="source"></param>
311     ''' <returns></returns>
312     <Extension>
313     Public Function GroupByKey(Of T As INamedValue)(source As IEnumerable(Of T)) As NamedCollection(Of T)()
314         Return source _
315             .GroupBy(Function(o) o.Key) _
316             .Select(Function(g)
317                         Return New NamedCollection(Of T) With {
318                              .Name = g.Key,
319                              .Value = g.ToArray
320                          }
321                     End Function) _
322             .ToArray
323     End Function
324
325     ''' <summary>
326     ''' Retrieve all items' value data.
327     ''' </summary>
328     ''' <typeparam name="T"></typeparam>
329     ''' <param name="source"></param>
330     ''' <returns></returns>
331     <MethodImpl(MethodImplOptions.AggressiveInlining)>
332     <Extension>
333     Public Function Values(Of T)(source As IEnumerable(Of NamedValue(Of T))) As T()
334         Return source _
335             .Select(Function(x) x.Value) _
336             .ToArray
337     End Function
338
339     <MethodImpl(MethodImplOptions.AggressiveInlining)>
340     <Extension>
341     Public Function Values(Of T, V)(src As IEnumerable(Of KeyValuePair(Of T, V))) As V()
342         Return src.SafeQuery.Select(Function(x) x.Value).ToArray
343     End Function
344
345     ''' <summary>
346     ''' gets all <see cref="INamedValue.Key"/> values
347     ''' </summary>
348     ''' <typeparam name="T"></typeparam>
349     ''' <param name="source"></param>
350     ''' <param name="distinct"></param>
351     ''' <returns></returns>
352     <Extension>
353     Public Function Keys(Of T As INamedValue)(source As IEnumerable(Of T), Optional distinct As Boolean = FalseAs List(Of String)
354         Dim list As IEnumerable(Of String) = source.Select(Function(o) o.Key)
355         If distinct Then
356             list = list.Distinct
357         End If
358         Return list.AsList
359     End Function
360
361     <MethodImpl(MethodImplOptions.AggressiveInlining)>
362     <Extension>
363     Public Function Keys(Of K, V)(source As IEnumerable(Of IGrouping(Of K, V))) As K()
364         Return source _
365             .Select(Function(x) x.Key) _
366             .ToArray
367     End Function
368
369 #If FRAMEWORD_CORE Then
370
371     ''' <summary>
372     ''' Get a specific item value from the target collction data using its UniqueID property,
373     ''' (请注意,请尽量不要使用本方法,因为这个方法的效率有些低,对于获取<see cref="INamedValue">
374     ''' </see>类型的集合之中的某一个对象,请尽量先转换为字典对象,在使用该字典对象进行查找以提高代码效率,使用本方法的优点是可以选择忽略<paramref name="uid">
375     ''' </paramref>参数之中的大小写,以及对集合之中的存在相同的Key的这种情况的容忍)
376     ''' </summary>
377     ''' <typeparam name="T"></typeparam>
378     ''' <param name="source"></param>
379     ''' <param name="uid"></param>
380     ''' <param name="IgnoreCase"></param>
381     ''' <returns></returns>
382     ''' <remarks></remarks>
383     <ExportAPI("Get.Item")>
384     <Extension> Public Function GetByKey(Of T As INamedValue)(
385                                        source As IEnumerable(Of T),
386                                           uid As String,
387                           Optional ignoreCase As StringComparison = StringComparison.Ordinal) _
388                                               As T
389
390         Dim find As T = LinqAPI.DefaultFirst(Of T) _
391  _
392             () <= From x As T
393                   In source
394                   Where String.Equals(uid, x.Key, ignoreCase)
395                   Select x
396
397         Return find
398     End Function
399
400     <MethodImpl(MethodImplOptions.AggressiveInlining)>
401     <Extension> Public Function GetByKey(Of T As INamedValue)(
402                                        source As IEnumerable(Of T),
403                                           uid As String,
404                           Optional ignoreCase As Boolean = False) _
405                                               As T
406         Return source.GetByKey(uid, If(ignoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal))
407     End Function
408 #End If
409
410     ''' <summary>
411     ''' Dictionary object contains the specific <see cref="NamedValue(Of T).Name"/>?
412     ''' </summary>
413     ''' <typeparam name="T"></typeparam>
414     ''' <param name="table"></param>
415     ''' <param name="k"></param>
416     ''' <returns></returns>
417     ''' 
418     <MethodImpl(MethodImplOptions.AggressiveInlining)>
419     <Extension>
420     Public Function ContainsKey(Of T As INamedValue)(table As Dictionary(Of T), k As NamedValue(Of T)) As Boolean
421         Return table.ContainsKey(k.Name)
422     End Function
423
424     ''' <summary>
425     ''' Dictionary object contains the specific <see cref="NamedValue(Of T).Name"/>?
426     ''' </summary>
427     ''' <typeparam name="T"></typeparam>
428     ''' <param name="table"></param>
429     ''' <param name="k"></param>
430     ''' <returns></returns>
431     ''' 
432     <MethodImpl(MethodImplOptions.AggressiveInlining)>
433     <Extension>
434     Public Function ContainsKey(Of T)(table As Dictionary(Of String, T), k As NamedValue(Of T)) As Boolean
435         Return table.ContainsKey(k.Name)
436     End Function
437
438     ''' <summary>
439     ''' Converts the interface object into a Dictionary object.
440     ''' </summary>
441     ''' <typeparam name="T"></typeparam>
442     ''' <typeparam name="V"></typeparam>
443     ''' <param name="source"></param>
444     ''' <returns></returns>
445     ''' 
446     <MethodImpl(MethodImplOptions.AggressiveInlining)>
447     <Extension>
448     Public Function DictionaryData(Of T, V)(source As IReadOnlyDictionary(Of T, V)) As Dictionary(Of T, V)
449         Return source.ToDictionary(Function(x) x.Key, Function(x) x.Value)
450     End Function
451
452     ''' <summary>
453     ''' Creates the dictionary for string converts to enum value.
454     ''' (接受的泛型类型必须是枚举类型)
455     ''' </summary>
456     ''' <typeparam name="T"></typeparam>
457     ''' <param name="lcaseKey"></param>
458     ''' <param name="usingDescription"></param>
459     ''' <returns></returns>
460     Public Function EnumParser(Of T As Structure)(Optional lcaseKey As Boolean = TrueOptional usingDescription As Boolean = FalseAs Dictionary(Of String, T)
461         Dim values As [Enum]() = Enums(Of T)().Select(Function(e) DirectCast(CType(e, Object), [Enum])).ToArray
462         Dim [case] = If(lcaseKey, Function(key$) LCase(key), Function(key$) key)
463
464         If usingDescription Then
465             Return values.ToDictionary(
466                 Function(e) [case](key:=e.Description),
467                 Function(e) DirectCast(CType(e, Object), T))
468         Else
469             Return values.ToDictionary(
470                 Function(e) [case](key:=e.ToString),
471                 Function(e) DirectCast(CType(e, Object), T))
472         End If
473     End Function
474
475     <MethodImpl(MethodImplOptions.AggressiveInlining)>
476     <Extension>
477     Public Function NamedValues(maps As IEnumerable(Of IDMap)) As NamedValue(Of String)()
478         Return maps _
479             .Select(Function(m) New NamedValue(Of String)(m.Key, m.Maps)) _
480             .ToArray
481     End Function
482
483     ''' <summary>
484     ''' Convert the dictionary table as the <see cref="NamedValue(Of T)"/> collection.
485     ''' (将目标字典之中的键值对转换为被命名为的变量值)
486     ''' </summary>
487     ''' <typeparam name="T"></typeparam>
488     ''' <param name="table"></param>
489     ''' <returns></returns>
490     <MethodImpl(MethodImplOptions.AggressiveInlining)>
491     <Extension>
492     Public Function NamedValues(Of T)(table As Dictionary(Of String, T)) As NamedValue(Of T)()
493         Return table _
494             .Select(Function(k)
495                         Return New NamedValue(Of T) With {
496                             .Name = k.Key,
497                             .Value = k.Value
498                         }
499                     End Function) _
500             .ToArray
501     End Function
502
503     <Extension>
504     Public Iterator Function IterateNameValues(Of T)(table As Dictionary(Of String, T)) As IEnumerable(Of NamedValue(Of T))
505         For Each map As KeyValuePair(Of String, T) In table
506             Yield New NamedValue(Of T) With {
507                 .Name = map.Key,
508                 .Value = map.Value
509             }
510         Next
511     End Function
512
513     <Extension>
514     Public Iterator Function IterateNameCollections(Of T)(table As Dictionary(Of String, T())) As IEnumerable(Of NamedCollection(Of T))
515         For Each map As KeyValuePair(Of String, T()) In table
516             Yield New NamedCollection(Of T)(map.Key, map.Value)
517         Next
518     End Function
519
520     <Extension>
521     Public Function NameValueCollection(maps As IEnumerable(Of IDMap)) As NameValueCollection
522         Dim nc As New NameValueCollection
523
524         For Each m As IDMap In maps
525             Call nc.Add(m.Key, m.Maps)
526         Next
527
528         Return nc
529     End Function
530
531     ''' <summary>
532     ''' 获取得到的集合对象是一个安全的集合对象,不存在的键名会直接返回空值
533     ''' </summary>
534     ''' <param name="maps"></param>
535     ''' <returns></returns>
536     <Extension>
537     Public Function NameValueCollection(maps As IEnumerable(Of NamedValue(Of String))) As NameValueCollection
538         Dim nc As New NameValueCollection
539
540         For Each m As NamedValue(Of StringIn maps
541             Call nc.Add(m.Name, m.Value)
542         Next
543
544         Return nc
545     End Function
546
547     <Extension> Public Sub SortByValue(Of V, T)(ByRef table As Dictionary(Of V, T), Optional desc As Boolean = False)
548         Dim orders As KeyValuePair(Of V, T)()
549         Dim out As New Dictionary(Of V, T)
550
551         If Not desc Then
552             orders = table.OrderBy(Function(p) p.Value).ToArray
553         Else
554             orders = table _
555                 .OrderByDescending(Function(p) p.Value) _
556                 .ToArray
557         End If
558
559         For Each k As KeyValuePair(Of V, T) In orders
560             Call out.Add(k.Key, k.Value)
561         Next
562
563         table = out
564     End Sub
565
566     ''' <summary>
567     ''' 按照键名对字典进行重新排序
568     ''' </summary>
569     ''' <typeparam name="V"></typeparam>
570     ''' <typeparam name="T"></typeparam>
571     ''' <param name="table"></param>
572     ''' <param name="desc">默认为从小到大的升序排序</param>
573     <Extension> Public Sub SortByKey(Of V, T)(ByRef table As Dictionary(Of V, T), Optional desc As Boolean = False)
574         Dim orders As V()
575         Dim out As New Dictionary(Of V, T)
576
577         If Not desc Then
578             orders = table.Keys.OrderBy(Function(k) k).ToArray
579         Else
580             orders = table.Keys _
581                 .OrderByDescending(Function(k) k) _
582                 .ToArray
583         End If
584
585         For Each k As V In orders
586             Call out.Add(k, table(k))
587         Next
588
589         table = out
590     End Sub
591
592     ''' <summary>
593     ''' Determines whether the <see cref="NameValueCollection"/> contains the specified key.
594     ''' </summary>
595     ''' <param name="d"></param>
596     ''' <param name="key$">The key to locate in the <see cref="NameValueCollection"/></param>
597     ''' <returns>true if the System.Collections.Generic.Dictionary`2 contains an element with
598     ''' the specified key; otherwise, false.</returns>
599     ''' 
600     <MethodImpl(MethodImplOptions.AggressiveInlining)>
601     <Extension>
602     Public Function ContainsKey(d As NameValueCollection, key$) As Boolean
603         Return Not String.IsNullOrEmpty(d(key))
604     End Function
605
606     <Extension>
607     Public Function Join(Of T, V)(d As Dictionary(Of T, V), name As T, value As V) As Dictionary(Of T, V)
608         d(name) = value
609         Return d
610     End Function
611
612     ''' <summary>
613     ''' 请注意,这里的类型约束只允许枚举类型
614     ''' </summary>
615     ''' <typeparam name="T"></typeparam>
616     ''' <returns></returns>
617     ''' 
618     <MethodImpl(MethodImplOptions.AggressiveInlining)>
619     Public Function ParserDictionary(Of T As Structure)() As Dictionary(Of String, T)
620         Return Enums(Of T).ToDictionary(Function(x) DirectCast(CType(x, Object), [Enum]).Description)
621     End Function
622
623     ''' <summary>
624     ''' Data exists and not nothing
625     ''' </summary>
626     ''' <typeparam name="T"></typeparam>
627     ''' <param name="d"></param>
628     ''' <param name="key"></param>
629     ''' <returns></returns>
630     ''' 
631     <MethodImpl(MethodImplOptions.AggressiveInlining)>
632     <Extension>
633     Public Function HaveData(Of T)(d As Dictionary(Of T, String), key As T) As Boolean
634         Return d.ContainsKey(key) AndAlso Not String.IsNullOrEmpty(d(key))
635     End Function
636
637     <Extension>
638     Public Function ToDictionary(nc As NameValueCollection) As Dictionary(Of StringString)
639         Dim hash As New Dictionary(Of StringString)
640
641         For Each key As String In nc.AllKeys
642             hash(key) = nc(key)
643         Next
644
645         Return hash
646     End Function
647
648     <MethodImpl(MethodImplOptions.AggressiveInlining)>
649     <Extension>
650     Public Function ToDictionary(Of K, V, KOut, VOut)(input As IEnumerable(Of KeyValuePair(Of K, V)), key As Func(Of K, V, KOut), value As Func(Of K, V, VOut)) As Dictionary(Of KOut, VOut)
651         Return input.ToDictionary(Function(tuple) key(tuple.Key, tuple.Value),
652                                   Function(tuple) value(tuple.Key, tuple.Value))
653     End Function
654
655     Const sourceEmpty$ = "Source is nothing, returns empty dictionary table!"
656
657     ''' <summary>
658     ''' Creates a <see cref="System.Collections.Generic.Dictionary"/>`2 from an <see cref="System.Collections.Generic.IEnumerable"/>`1
659     ''' according to a specified key selector function.
660     ''' </summary>
661     ''' <typeparam name="T">Unique identifier provider <see cref="INamedValue.Key"/></typeparam>
662     ''' <param name="source"></param>
663     ''' <returns></returns>
664     <Extension>
665     Public Function ToDictionary(Of T As INamedValue)(source As IEnumerable(Of T)) As Dictionary(Of T)
666         If source Is Nothing Then
667 #If DEBUG Then
668             Call sourceEmpty.Warning
669 #End If
670             Return New Dictionary(Of T)
671         End If
672
673         Dim i As Integer = 0
674         Dim keys As New List(Of String)
675
676         Try
677             With New Dictionary(Of T)
678                 For Each item As T In source
679                     Call .Add(item.Key, item)
680                     Call keys.Add(item.Key)
681
682                     i += 1
683                 Next
684
685                 Return .ByRef
686             End With
687         Catch ex As Exception
688             ex = New Exception("key --> [ " & source(i).Key & " ]", ex)
689             ex = New Exception("keys --> " & keys.GetJson, ex)
690
691             Throw ex
692         End Try
693     End Function
694
695     ''' <summary>
696     ''' 将命名变量对象进行降维,名字作为键名,值作为键值,生成字典
697     ''' </summary>
698     ''' <typeparam name="T"></typeparam>
699     ''' <param name="table"></param>
700     ''' <returns></returns>
701     <MethodImpl(MethodImplOptions.AggressiveInlining)>
702     <Extension>
703     Public Function FlatTable(Of T)(table As Dictionary(Of NamedValue(Of T))) As Dictionary(Of String, T)
704         Return table.ToDictionary(Function(item) item.Key,
705                                   Function(item) item.Value.Value)
706     End Function
707
708     <Extension> Public Function Add(Of TKey, TValue)(ByRef list As List(Of KeyValuePair(Of TKey, TValue)), key As TKey, value As TValue) As List(Of KeyValuePair(Of TKey, TValue))
709         If list Is Nothing Then
710             list = New List(Of KeyValuePair(Of TKey, TValue))
711         End If
712         list += New KeyValuePair(Of TKey, TValue)(key, value)
713         Return list
714     End Function
715
716     ''' <summary>
717     ''' Adds an object to the end of the List`1.
718     ''' </summary>
719     ''' <typeparam name="TKey"></typeparam>
720     ''' <typeparam name="TValue"></typeparam>
721     ''' <param name="list"></param>
722     ''' <param name="key"></param>
723     ''' <param name="value"></param>
724     ''' <returns></returns>
725     <Extension> Public Function Add(Of TKey, TValue)(ByRef list As List(Of KeyValuePairObject(Of TKey, TValue)), key As TKey, value As TValue) As List(Of KeyValuePairObject(Of TKey, TValue))
726         If list Is Nothing Then
727             list = New List(Of KeyValuePairObject(Of TKey, TValue))
728         End If
729         list += New KeyValuePairObject(Of TKey, TValue)(key, value)
730         Return list
731     End Function
732
733     ''' <summary>
734     ''' 使用这个函数应该要确保value是没有重复的,假若<paramref name="removeDuplicated"/>是默认值的话.
735     ''' </summary>
736     ''' <typeparam name="T"></typeparam>
737     ''' <typeparam name="V"></typeparam>
738     ''' <param name="d"></param>
739     ''' <returns></returns>
740     <Extension>
741     Public Function ReverseMaps(Of T, V)(d As Dictionary(Of T, V), Optional removeDuplicated As Boolean = FalseAs Dictionary(Of V, T)
742         If removeDuplicated Then
743             Dim groupsData = From x In d Select x Group x By x.Value Into Group
744             Return groupsData.ToDictionary(
745                 Function(g) g.Value,
746                 Function(g) g.Group.First.Key)
747         Else
748             Return d.ToDictionary(
749                 Function(x) x.Value,
750                 Function(x) x.Key)
751         End If
752     End Function
753
754     ''' <summary>
755     ''' 一次性地使用一个键名的集合从字典之中选出一组数据
756     ''' </summary>
757     ''' <typeparam name="T"></typeparam>
758     ''' <typeparam name="V"></typeparam>
759     ''' <param name="d"></param>
760     ''' <param name="keys"></param>
761     ''' <param name="skipNonExist"></param>
762     ''' <returns></returns>
763     <Extension>
764     Public Function Selects(Of T, V)(d As Dictionary(Of T, V), keys As IEnumerable(Of T), Optional skipNonExist As Boolean = FalseAs V()
765         If skipNonExist Then
766             Return keys _
767                 .Where(AddressOf d.ContainsKey) _
768                 .Select(Function(k) d(k)) _
769                 .ToArray
770         Else
771             Return keys.Select(Function(k) d(k)).ToArray
772         End If
773     End Function
774
775     <MethodImpl(MethodImplOptions.AggressiveInlining)>
776     <Extension>
777     Public Function [Select](Of K, V, T)(source As IEnumerable(Of KeyValuePair(Of K, V)), project As Func(Of K, V, T)) As IEnumerable(Of T)
778         Return source.Select(Function(value) project(value.Key, value.Value))
779     End Function
780
781     <MethodImpl(MethodImplOptions.AggressiveInlining)>
782     <Extension>
783     Public Function [Select](Of V, T)(source As IEnumerable(Of KeyValuePair(Of String, V)), project As Func(Of String, V, T)) As IEnumerable(Of T)
784         Return source.Select(Function(value) project(value.Key, value.Value))
785     End Function
786 End Module