You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 14:36:02