如何使用CompareTo对比两个List(Of T)并将变更保存到新列表
需求背景
我已将两个DataTable转换为两个List(Of ISAACService),尝试通过CompareTo()方法完成列表对比,UANR为行主键,需要识别出新增、删除、修改的行,将有变更的对象添加到BindingList后传递到UltraGrid做高亮展示。
最初写的嵌套循环对比逻辑存在所有对比行都被添加到BindingList的问题,优化后相同内容对比可返回空列表,但现在需要引入CompareTo方法,实现仅对UANR相同的行做属性对比,正确筛选变更条目。
现有代码实现
基类定义
Public MustInherit Class ISAACServiceBase ReadOnly Property K_Art As String ReadOnly Property UANR As String ReadOnly Property Ueberbegriff As String ReadOnly Property Benennung As String ReadOnly Property Anzahl As Double ReadOnly Property Einheit As String ReadOnly Property Einzelkosten As Double 'ReadOnly Property Gesamtmenge As Integer ReadOnly Property Summencode As String Public Sub New() End Sub Public Sub New(kostenArt As String, uanr As String, ueberbegriff As String, benennung As String, anzahl As Double, einheit As String, einzelkosten As Double, sumcode As String) Me.K_Art = kostenArt Me.UANR = uanr Me.Ueberbegriff = ueberbegriff Me.Benennung = benennung Me.Anzahl = anzahl Me.Einheit = einheit Me.Einzelkosten = einzelkosten 'Me.Gesamtmenge = gesamtmenge Me.Summencode = sumcode End Sub End Class
CompareTo方法实现
Public Function CompareTo(other As ISAACService) As Integer Implements IComparable(Of ISAACService).CompareTo If other.GetType() Is GetType(ISAACService) Then other = CType(other, ISAACService) If Me.UANR > other.UANR Then Return 1 ElseIf Me.UANR < other.UANR Then Return -1 Else Return 0 End If End If Return 0 End Function
DataTable转列表方法
Private Function ConvertDataTableToListOfISAACService(dt As DataTable, lst As List(Of ISAACService)) As List(Of ISAACService) For Each row As DataRow In dt.Rows Dim ISAAC As New ISAACService(row(KostenArt).ToString, row(UANR).ToString, row(Ueberbegriff).ToString, row(Benennung).ToString, CDbl(row(Anzahl)), row(Einheit).ToString, CDbl(row(Einzelkosten)), row(Summencode).ToString) lst.Add(ISAAC) Next Return lst End Function
初始对比逻辑(存在全量添加问题)
Private Function CompareDataTables() As BindingList(Of ISAACService) '遍历两个列表完成对比 For Each item1 As ISAACService In lst1 For Each item2 As ISAACService In lst2 If item1.CompareTo(item2) = 1 Then resultList.Add(item1) ElseIf item1.CompareTo(item2) = -1 Then resultList.Add(item1) End If Next Next Return resultList End Function
优化后对比逻辑(仅识别新增删除,未处理属性修改)
Private Function CompareDataTables() As BindingList(Of ISAACService) '遍历两个列表删除相同行 Dim lst3 = CombineLists(lst1, lst2) For Each s In lst3 If lst1.Contains(s) Then lst1.Remove(s) ElseIf lst2.Contains(s) Then lst2.Remove(s) End If Next For Each item1 In lst1 resultList.Add(item1) Next For Each item2 In lst2 resultList.Add(item2) Next Return resultList End Function
修复方案
现有逻辑的核心问题:
- 现有
CompareTo仅对比UANR主键,无法识别同主键下的属性变更 List.Contains默认对比对象引用而非属性值,同主键不同属性的对象会被判定为不同,无法正确识别修改- 嵌套循环时间复杂度为O(n²),数据量大时性能差
第一步:新增属性对比方法
在ISAACService类中添加以下方法,用于判断同主键对象的属性是否完全一致:
' 判断两个同UANR对象的属性是否完全相同 Public Function HasSameProperties(other As ISAACService) As Boolean If Me.CompareTo(other) <> 0 Then Return False ' 主键不同直接返回 Return Me.K_Art = other.K_Art AndAlso Me.Ueberbegriff = other.Ueberbegriff AndAlso Me.Benennung = other.Benennung AndAlso Me.Anzahl = other.Anzahl AndAlso Me.Einheit = other.Einheit AndAlso Me.Einzelkosten = other.Einzelkosten AndAlso Me.Summencode = other.Summencode End Function
第二步:重写对比逻辑
使用字典做UANR映射,将查询复杂度降低到O(1),同时覆盖新增、删除、修改三种场景:
Private Function CompareDataTables() As BindingList(Of ISAACService) Dim resultList As New BindingList(Of ISAACService) ' 转字典加速查询,key为UANR,value为对象 Dim oldDict = lst1.ToDictionary(Function(x) x.UANR) Dim newDict = lst2.ToDictionary(Function(x) x.UANR) ' 识别删除、修改的行 For Each oldItem In lst1 If Not newDict.ContainsKey(oldItem.UANR) Then ' 旧列表有、新列表无:删除状态 resultList.Add(oldItem) Else ' 主键相同,判断属性是否变更 Dim newItem = newDict(oldItem.UANR) If Not oldItem.HasSameProperties(newItem) Then ' 属性有差异:修改状态,可根据需求调整添加新对象/新旧都加 resultList.Add(newItem) End If End If Next ' 识别新增的行 For Each newItem In lst2 If Not oldDict.ContainsKey(newItem.UANR) Then ' 新列表有、旧列表无:新增状态 resultList.Add(newItem) End If Next Return resultList End Function
内容的提问来源于stack exchange,提问作者idontgetit
相关产品推荐
相关产品推荐

