如何从数据表中提取所有唯一/不同的行并将这些行保存在具有相同列的新数据表中?

How can I extract all Unique / Distinct Rows from a Datatable and save these rows in a new Datatable with same Columns?

问题

我有一个包含多个列和行的数据表。这些列名称之一是“登录”。此 DataTable 中的某些行具有相同的列“登录”。例如,“登录”为 test123 的 2 行。我需要一个新的 DataTable 只包含这 2 行中的一个(哪一个无关紧要)。

问题

如何从旧数据表创建新数据表,过滤掉“登录”列中具有重复条目的行。新的 DataTable 应该与旧的具有相同的结构/列。实际上,在应用过滤器并找到一些匹配项后,只有 Rows.Count 发生变化。

到目前为止我尝试了什么

几个选项允许根据特定列的值过滤 DataTable 的 DataRow,以生成具有结果 DataRow 的新 DataTable。

考虑 - 既然你提到了 - selected 哪个 DataRow 并不重要,即任何 duplicate DataRow 都可以:
(如果 select 的 DataRow 在某些时候变得重要,您还可以 OrderBy() 使用另一个列的值进行分组,然后从中选择第一个或最后一个 DataRow有序 collection)

按列的值对数据行进行分组:

  • 使用列的值对源 DataTable 的数据行进行分组
  • Select 每个分组的第一个 DataRow
  • 调用CopyToDataTable()方法生成新的DataTable

导致:

Dim newDt = [DataTable].AsEnumerable().
    GroupBy(Function(r) r("[Column Name]")).
    Select(Function(g) g.First()).
    CopyToDataTable()

使用自定义 EqualityComparer:

  • 构建一个简单的 EqualityComparer class 来比较两个数据行的同一列的值 objects
  • 使用 Distinct() 方法并传递自定义 EqualityComparer,使用用作比较器的列的名称进行初始化
  • 调用CopyToDataTable()方法

此方法的优点是可重用(即,您无需重建查询,只需使用要比较的列的名称初始化比较器即可)

导致:

Dim newDt = [DataTable].AsEnumerable().
Distinct(New DataRowColumnComparer("[Column Name]")).
CopyToDataTable()

自定义 EqualityComparer:
这是一种基本的比较器。您当然可以扩展它以使用不同的索引器(表示列索引的整数或 DataColumn 引用)。

Public Class DataRowColumnComparer
    Implements IEqualityComparer(Of DataRow)

    Private ReadOnly t As String = String.Empty

    Public Sub New(key As String)
        If String.IsNullOrEmpty(key) Then Throw New ArgumentException("Empty key")
        t = key
    End Sub

    Public Overloads Function Equals(dr1 As DataRow, dr2 As DataRow) As Boolean Implements IEqualityComparer(Of DataRow).Equals
        If dr1 Is Nothing AndAlso dr2 Is Nothing Then Return True
        If dr1 Is Nothing OrElse dr2 Is Nothing Then Return False
        Return dr1(t).Equals(dr2(t))
    End Function

    Public Overloads Function GetHashCode(dr As DataRow) As Integer Implements IEqualityComparer(Of DataRow).GetHashCode
        If dr(t) Is Nothing OrElse dr(t) Is DBNull.Value Then Return 0
        Return dr(t).GetHashCode()
    End Function
End Class