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