.Net集合的查找、排序和分组

 

以批判的眼光看待自己,以欣赏的眼光看待他人。

集合,在编写程序时经常用到,这里根据个人的应用经验,简单的描述一下对集合的数据查找、排序以及分组的理解。以下也只是随兴书写,并无高深的技术解析,所写内容更无很高的应用及影响深远的价值,纯属个人随笔。

 

● 查找数据

在一个集合中查找满足指定条件的数据,是一件很容易的事,应用也很广泛。实现方法,即可以用传统的循环加条件判断,也可以直接调用.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

 

记住:爱情是以物质为基础的奢侈的精神享受!

 

posted @ 2013-05-07 22:57  静水无踪  阅读(640)  评论(0编辑  收藏  举报