以批判的眼光看待自己,以欣赏的眼光看待他人。
集合,在编写程序时经常用到,这里根据个人的应用经验,简单的描述一下对集合的数据查找、排序以及分组的理解。以下也只是随兴书写,并无高深的技术解析,所写内容更无很高的应用及影响深远的价值,纯属个人随笔。
● 查找数据
在一个集合中查找满足指定条件的数据,是一件很容易的事,应用也很广泛。实现方法,即可以用传统的循环加条件判断,也可以直接调用.Net自身提供的Find和FindAll方法。
传统方法实现
1: For Each oSozaiWrtk As sozaiWrtkListInfoDto In Me.lstSozaiWrtkInfo
2: If oSozaiWrtk.wrtkYmd.val = oSozaiWrtkIn.wrtkYmd.val AndAlso
3: oSozaiWrtk.wakuSubNo.val = oSozaiWrtkIn.wakuSubNo.val AndAlso
4: oSozaiWrtk.wakutoriId.val <> oSozaiWrtkIn.wakutoriId.val AndAlso
5: oSozaiWrtk.hyojiChannelId = oSozaiWrtkIn.hyojiChannelId Then
6: lstSozaiWrtk.Add(oSozaiWrtk)
7: End If
8: Next
.Net提供的方法实现
1: lstSozaiWrtk = Array.FindAll(
2: Me.lstSozaiWrtkInfo,
3: Function(oSozaiWrtk As sozaiWrtkListInfoDto)
4: If oSozaiWrtk.wrtkYmd.val = oSozaiWrtkIn.wrtkYmd.val AndAlso
5: oSozaiWrtk.wakuSubNo.val = oSozaiWrtkIn.wakuSubNo.val AndAlso
6: oSozaiWrtk.wakutoriId.val <> oSozaiWrtkIn.wakutoriId.val AndAlso
7: oSozaiWrtk.hyojiChannelId = oSozaiWrtkIn.hyojiChannelId Then
8: Return True
9: Else
10: Return False
11: End If
12: End Function)
事实上,.Net还提供了Exists(检查满足指定条件的数据是否存在)、FindIndex(搜索与指定条件相匹配的数据在集合中的索引)等诸多以泛型Predicate为参数的方法,其用法同上面的FindAll类似。在编写程序时,尽量考虑用.Net提供的方法实现,在程序编写速度、维护以及运行效率方面都有很大的帮助。
● 数据排序
.Net中集合的排序有两种方式,常用的方法是利用DataTable来排序,模拟Sql中的Order By实现。这里要说的是对数组或泛型List进行排序,实现思路是用.Net集合中的Sort方法,通过类内部实现IComparable排序接口,或以实现IComparer接口的类为参数的方式实现排序。
定义排序类,并继承IComparer接口,实现Compare方法。
1: ''' <summary>
2: ''' WakuTori信息排序
3: ''' </summary>
4: ''' <remarks>
5: ''' WakuTori信息的放送日、Channel、Multi排序
6: ''' </remarks>
7: Public Class WakuToriSortByMany
8: Implements IComparer
9:
10: ''' <summary>
11: ''' WakuTori信息排序
12: ''' </summary>
13: ''' <param name="oFirst">对象1</param>
14: ''' <param name="oSecond">对象1</param>
15: ''' <returns>相对值</returns>
16: Public Function Compare(
17: ByVal oFirst As Object,
18: ByVal oSecond As Object
19: ) As Integer Implements IComparer.Compare
20:
21: Dim iFlg As Integer = Nothing
22:
23: Dim oWakuToriFirst As wakutoriInfoDto = Nothing
24: Dim oWakuToriSecond As wakutoriInfoDto = Nothing
25:
26: ' 放送日
27: Dim iHosoYmdFirst As Integer = Nothing
28: Dim iHosoYmdSecond As Integer = Nothing
29:
30: ' Channel
31: Dim sChannelFirst As String = Nothing
32: Dim sChannelSecond As String = Nothing
33:
34: ' Multi
35: Dim sMultiFirst As String = Nothing
36: Dim sMultiSecond As String = Nothing
37:
38: oWakuToriFirst = DirectCast(oFirst, wakutoriInfoDto)
39: oWakuToriSecond = DirectCast(oSecond, wakutoriInfoDto)
40:
41: ' 比较放送日
42: Int32.TryParse(oWakuToriFirst.hosoYmd.val, iHosoYmdFirst)
43: Int32.TryParse(oWakuToriSecond.hosoYmd.val, iHosoYmdSecond)
44: iFlg = Comparer(Of Integer).Default.Compare(iHosoYmdFirst, iHosoYmdSecond)
45:
46: If iFlg = 0 Then
47:
48: ' 比较Channel
49: sChannelFirst = oWakuToriFirst.channel
50: sChannelSecond = oWakuToriSecond.channel
51: iFlg = Comparer(Of String).Default.Compare(sChannelFirst, sChannelSecond)
52:
53: If iFlg = 0 Then
54:
55: ' 比较Multi
56: sMultiFirst = oWakuToriFirst.multiRetsu
57: sMultiSecond = oWakuToriSecond.multiRetsu
58: iFlg = Comparer(Of String).Default.Compare(sMultiFirst, sMultiSecond)
59:
60: Return iFlg
61:
62: Else
63: Return iFlg
64: End If
65:
66: Else
67: Return iFlg
68: End If
69:
70: End Function
71:
72: End Class
自定义类时,继承IComparable接口,实现CompareTo方法。
1: Public Class KihonProgJoho
2: Implements IComparable
3:
4: Private _sYobi As String
5: Private _iChannelIndex As Integer
6: Private _sFromTime As String
7: Private _sToTime As String
8:
9: Public Property sYobi() As String
10: Get
11: Return _sYobi
12: End Get
13: Set(ByVal value As String)
14: _sYobi = value
15: End Set
16: End Property
17:
18: Public Property iChannelIndex() As Integer
19: Get
20: Return _iChannelIndex
21: End Get
22: Set(ByVal value As Integer)
23: _iChannelIndex = value
24: End Set
25: End Property
26:
27: Public Property sFromTime() As String
28: Get
29: Return _sFromTime
30: End Get
31: Set(ByVal value As String)
32: _sFromTime = value
33: End Set
34: End Property
35:
36: Public Property sToTime() As String
37: Get
38: Return _sToTime
39: End Get
40: Set(ByVal value As String)
41: _sToTime = value
42: End Set
43: End Property
44:
45: ''' <summary>
46: ''' 当前实例与同一类型的另一个对象进行比较
47: ''' </summary>
48: ''' <param name="obj">对象</param>
49: ''' <returns>比较的相对值</returns>
50: ''' <remarks></remarks>
51: Public Function CompareTo(
52: ByVal obj As Object
53: ) As Integer Implements IComparable.CompareTo
54: Dim oKihonProgJoho As KihonProgJoho = TryCast(obj, KihonProgJoho)
55:
56: If oKihonProgJoho IsNot Nothing Then
57: Dim iOriginYobiIndex As Integer = ToYobIndex(_sYobi)
58: Dim iObjYobiIndex As Integer = ToYobIndex(oKihonProgJoho.sYobi)
59:
60: If iOriginYobiIndex = iObjYobiIndex Then
61: Dim iOriginChannelPtnId As Integer = _iChannelIndex
62: Dim iObjChannelPtnId As Integer = oKihonProgJoho.iChannelIndex
63:
64: If iOriginChannelPtnId = iObjChannelPtnId Then
65: Dim iOriginFromTime As Integer = CInt(_sFromTime)
66: Dim iObjFromTime As Integer = CInt(oKihonProgJoho.sFromTime)
67:
68: If iOriginFromTime = iObjFromTime Then
69: Dim iOriginToTime As Integer = CInt(_sToTime)
70: Dim iObjToTime As Integer = CInt(oKihonProgJoho.sToTime)
71:
72: Return iOriginToTime - iObjToTime
73: Else
74: Return iOriginFromTime - iObjFromTime
75: End If
76: Else
77: Return iOriginChannelPtnId - iObjChannelPtnId
78: End If
79: Else
80: Return iOriginYobiIndex - iObjYobiIndex
81: End If
82: Else
83: Return COMMON_FLAG.NASHI
84: End If
85: End Function
86:
87: End Class
由于.Net框架内部对集合的Sort方法的数据排序是采用快速排序算法,所以以上无论哪种方式,均为不稳定排序,亦即两个相等的元素多次排序后,其顺序并不会被保留。要实现稳定排序,需要自定义排序方法,用冒泡排序、基数排序和直接插入排序等稳定排序算法实现对集合的排序。稳定排序的具体实现,这里不再熬述。
● 数据分组
单个字段分组
1: Dim lstSozaiWrtkInfo() As sozaiWrtkListInfoDto = Nothing
2:
3: ' 分组结果
4: Dim lstDataSozai As IEnumerable(Of IGrouping(Of String, sozaiWrtkListInfoDto)) = Nothing
5:
6: ' 给lstSozaiWrtkInfo赋值
7: ' ……
8:
9: ' 分组
10: lstDataSozai = lstSozaiWrtkInfo.GroupBy(
11: Function(oSozaiWrtk) oSozaiWrtk.wrtkYmd.val)
12:
13: ' 循环访问所有组
14: For Each lstGroupByYmd As IGrouping(Of String, sozaiWrtkListInfoDto) In lstDataSozai
15:
16: ' 循环访问每一组
17: For Each oSozaiWrtkInfo As sozaiWrtkListInfoDto In lstGroupByYmd
18:
19: ' 业务逻辑
20: ' ……
21:
22: Next
23:
24: Next
多字段分组
根据个人的研究,多字段分组得分两种情况讨论。现今网上流行的做法都是直接把需要分组的字段写进匿名函数,如下:
1: lst.GroupBy(Function(k) New With {Key .Age = k.Age,
2: Key .Sex = k.Sex})
以上这种情况,只适合集合中的对象属性是基本型的,如果集合中的对象属性本身又是对象,那就是另一种情况了。
对于对象属性本身又是对象的情况,直接用上面的方法进行多列分组是不行的,只能一次对一个字段分组,多个字段嵌套分组。
1: Dim lstSozaiWrtkInfo() As sozaiWrtkListInfoDto = Nothing
2:
3: ' 分组结果
4: Dim lstDataSozaiByCMKeyk As IEnumerable(Of IGrouping(Of String, sozaiWrtkListInfoDto)) = Nothing
5: Dim lstDataSozaiByWt As IEnumerable(Of IGrouping(Of String, sozaiWrtkListInfoDto)) = Nothing
6:
7: ' 给lstSozaiWrtkInfo赋值
8: ' ……
9:
10: ' GroupBy「cmKeykId」
11: lstDataSozaiByCMKeyk = Me.lstSozaiWrtkInfo.GroupBy(
12: Function(oSozaiWrtk) oSozaiWrtk.cmKeykId.val)
13:
14: For Each lstGroupByCMKeyk As IGrouping(Of String, sozaiWrtkListInfoDto)
15: In lstDataSozaiByCMKeyk
16:
17: ' GroupBy「wakutoriId」
18: lstDataSozaiByWt = lstGroupByCMKeyk.GroupBy(
19: Function(oSozaiWrtk) oSozaiWrtk.wakutoriId.val)
20:
21: For Each lstGroupByWt As IGrouping(Of String, sozaiWrtkListInfoDto)
22: In lstDataSozaiByWt
23:
24: For Each oSozaiwrtk As sozaiWrtkListInfoDto In lstGroupByWt
25:
26: ' 业务逻辑
27: ' ……
28:
29: Next
30: Next
31: Next
记住:爱情是以物质为基础的奢侈的精神享受!