好的!我有两组订阅者信息,每组都有以下信息。
SubType(string),SubSchool(number),SubEffDate(date),SubTermDate(date),SubMethod(string),Verifiedby(string)等
我打算在数据表或列表中获取和保留数据。
如何比较两个集合(每个集合行和每个字段)并找到唯一行并将这些唯一行复制到另一个表/列表中?
示例: 在下面的订阅者 1 表第一行中,所有列值都不等于订阅者 2 的第一行。所以这一行将复制到另一个临时表。
订阅者 1 第二行(每列值)等于第一行订阅者 2(每列值),因此我们不会将订阅者 1 第二行复制到临时表中。
答案 0 :(得分:0)
创建一个实现 Subscriber
的类 IEquatable(Of Subscriber)
,然后您可以开始手动比较集合,或者像 Hursey 链接的文章中描述的那样。
理想情况下,您应该有一个可以进行比较的 ID,否则 - 如果需要比较每个字段 - 使用巧妙的哈希比较来排除所有不相等的记录。
这里有一个相当复杂的实现,它考虑了不同的字符串比较并尝试快速。
Public NotInheritable Class Subscriber
Implements IEquatable(Of Subscriber)
'Private Fields
<DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _HashCode As Int32?
<DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _Type As String
<DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _School As Int32
<DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _EffDate As DateTime
<DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _TermDate As DateTime
<DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _Method As String
<DebuggerBrowsable(DebuggerBrowsableState.Never)>
Private _VerifiedBy As String
Private Shared ReadOnly _TypeComparer As IEqualityComparer(Of String) = StringComparer.Ordinal
Private Shared ReadOnly _MethodComparer As IEqualityComparer(Of String) = StringComparer.OrdinalIgnoreCase
Private Shared ReadOnly _VerifiedByComparer As IEqualityComparer(Of String) = StringComparer.OrdinalIgnoreCase
'Constructors
Public Sub New(type As String, school As Int32, effDate As DateTime, termDate As DateTime, method As String, verifiedBy As String)
_Type = type
_School = school
_EffDate = effDate
_TermDate = termDate
_Method = method
_VerifiedBy = verifiedBy
End Sub
'Public Properties
Public Property Type As String
Get
Return _Type
End Get
Set(value As String)
_Type = value?.Normalize()
InvalidateHashCode()
End Set
End Property
Public Property School As Int32
Get
Return _School
End Get
Set(value As Int32)
_School = value
InvalidateHashCode()
End Set
End Property
Public Property EffDate As DateTime
Get
Return _EffDate
End Get
Set(value As DateTime)
_EffDate = value
InvalidateHashCode()
End Set
End Property
Public Property TermDate As DateTime
Get
Return _TermDate
End Get
Set(value As DateTime)
_TermDate = value
InvalidateHashCode()
End Set
End Property
Public Property Method As String
Get
Return _Method
End Get
Set(value As String)
_Type = value?.Normalize()
InvalidateHashCode()
End Set
End Property
Public Property VerifiedBy As String
Get
Return _VerifiedBy
End Get
Set(value As String)
_VerifiedBy = value?.Normalize()
InvalidateHashCode()
End Set
End Property
'Public Methods
Public Overrides Function Equals(obj As Object) As Boolean
If (TypeOf obj Is Subscriber) Then
Return Equals(DirectCast(obj, Subscriber))
End If
Return False
End Function
Public Overloads Function Equals(other As Subscriber) As Boolean Implements IEquatable(Of Subscriber).Equals
If (other Is Nothing) Then Return False
If (Object.ReferenceEquals(other, Me)) Then Return True
If (other.HashCode <> Me.HashCode) Then Return False
If (other._School <> Me._School) Then Return False
If (other._EffDate <> Me._EffDate) Then Return False
If (other._TermDate <> Me._TermDate) Then Return False
If (Not _TypeComparer.Equals(other._Type, Me._Type)) Then Return False
If (Not _MethodComparer.Equals(other._Method, Me._Method)) Then Return False
If (Not _VerifiedByComparer.Equals(other._VerifiedBy, Me._VerifiedBy)) Then Return False
Return True
End Function
Public Overrides Function GetHashCode() As Integer
Return HashCode
End Function
'Private Properties
Private ReadOnly Property HashCode As Int32
Get
Dim result As Int32? = _HashCode
If (result Is Nothing) Then
result = 8123498 Xor _TypeComparer.GetHashCode(_Type) Xor _School Xor _EffDate.GetHashCode() Xor _TermDate.GetHashCode() Xor _MethodComparer.GetHashCode(_Method) Xor _VerifiedByComparer.GetHashCode(_VerifiedBy)
_HashCode = result
End If
Return result
End Get
End Property
'Private Methods
Private Sub InvalidateHashCode()
_HashCode = Nothing
End Sub
End Class
然后您需要 LINQ 或以下类来比较集合:
Public Class SetComparison(Of TElement)
'Constructors
Public Sub New(set1 As IEnumerable(Of TElement), set2 As IEnumerable(Of TElement))
'Check lists
If (set1 Is Nothing) Then set1 = Array.Empty(Of Subscriber)()
If (set2 Is Nothing) Then set2 = Array.Empty(Of Subscriber)()
'Convert first set into a hash set
Dim nullCount1 As Int32 = 0
Dim hashSet1 As New HashSet(Of TElement)(set1.Count())
Dim duplicates1 As New Dictionary(Of TElement, Int32)()
For Each e As TElement In set1
If (e Is Nothing) Then
nullCount1 += 1
Continue For
End If
If (hashSet1.Contains(e)) Then
Dim count As Int32
If (duplicates1.TryGetValue(e, count)) Then
duplicates1.Item(e) = count + 1
Else
duplicates1.Item(e) = 1
End If
Else
hashSet1.Add(e)
End If
Next
'Convert second set into a hash set
Dim nullCount2 As Int32 = 0
Dim hashSet2 As New HashSet(Of TElement)(set2.Count())
Dim duplicates2 As New Dictionary(Of TElement, Int32)()
For Each e As TElement In set2
If (e Is Nothing) Then
nullCount2 += 1
Continue For
End If
If (hashSet2.Contains(e)) Then
Dim count As Int32
If (duplicates2.TryGetValue(e, count)) Then
duplicates2.Item(e) = count + 1
Else
duplicates2.Item(e) = 1
End If
Else
hashSet2.Add(e)
End If
Next
'Compare with each other
Dim hashSetInBoth As New HashSet(Of TElement)()
If (hashSet1.Count < hashSet2.Count) Then
For Each e As TElement In hashSet1
If (hashSet2.Remove(e)) Then
hashSetInBoth.Add(e)
End If
Next
For Each e As TElement In hashSetInBoth
hashSet1.Remove(e)
Next
Else
For Each e As TElement In hashSet2
If (hashSet1.Remove(e)) Then
hashSetInBoth.Add(e)
End If
Next
For Each e As TElement In hashSetInBoth
hashSet2.Remove(e)
Next
End If
'Assign results
OnlyInSet1 = hashSet1
OnlyInSet2 = hashSet2
InBothSets = hashSetInBoth
DuplicatesInSet1 = duplicates1
DuplicatesInSet2 = duplicates2
NullElementsInSet1 = nullCount1
NullElementsInSet2 = nullCount2
End Sub
'Public Properties
Public ReadOnly Property OnlyInSet1 As HashSet(Of TElement)
Public ReadOnly Property OnlyInSet2 As HashSet(Of TElement)
Public ReadOnly Property InBothSets As HashSet(Of TElement)
''' <summary>Dictionary with the duplicate elements of set 1 and the number of duplicates found for that element (a number of 2 means there have been 3 equal elements in the set, the original and 2 duplicates).</summary>
Public ReadOnly Property DuplicatesInSet1 As Dictionary(Of TElement, Int32)
''' <summary>Dictionary with the duplicate elements of set 2 and the number of duplicates found for that element (a number of 2 means there have been 3 equal elements in the set, the original and 2 duplicates).</summary>
Public ReadOnly Property DuplicatesInSet2 As Dictionary(Of TElement, Int32)
Public ReadOnly Property NullElementsInSet1 As Int32
Public ReadOnly Property NullElementsInSet2 As Int32
End Class
你会像这样使用它:
Sub Main(args As String())
'Generate some data
Dim list1 As New List(Of Subscriber)()
list1.Add(New Subscriber("Type1", 42, New Date(2021, 1, 1), New Date(2021, 1, 1), "Method1", "VerifiedBy"))
list1.Add(New Subscriber("Type2", 42, New Date(2021, 1, 1), New Date(2021, 1, 1), "Method1", "VerifiedBy"))
Dim list2 As New List(Of Subscriber)()
list2.Add(New Subscriber("Type3", 42, New Date(2021, 1, 1), New Date(2021, 1, 1), "Method1", "VerifiedBy"))
list2.Add(Nothing)
list2.Add(New Subscriber("Type2", 42, New Date(2021, 1, 1), New Date(2021, 1, 1), "Method1", "VerifiedBy"))
list2.Add(New Subscriber("Type3", 42, New Date(2021, 1, 1), New Date(2021, 1, 1), "Method1", "VerifiedBy"))
'Compare it
Dim comparison As New SetComparison(Of Subscriber)(list1, list2)
'Use it
Dim onlyInSet1 As HashSet(Of Subscriber) = comparison.OnlyInSet1
Dim onlyInSet2 As HashSet(Of Subscriber) = comparison.OnlyInSet2
Dim inBothSets As HashSet(Of Subscriber) = comparison.InBothSets
End Sub
答案 1 :(得分:0)
Here is my approach. Considering two data tables for Subscribers information.
Datatable Subscriber1 = New Datatable();
Datatable Subscriber2 = New Datatable();
int intColCount = 0;
for(int i=0; i< Subscriber1.Rows.Count;i++)
{
for(int j=0;j<Subscriber2.Rows.Count;j++)
{
intColcheck=0;
for(int c=0;c<Subscriber1.Columns.Count;c++)
{
if(Subscriber1.Rows[i][c].ToString()==Subscriber2.Rows[j][c].ToString())
{
intColcheck= intColcheck+ 1;
}
}
// If all the Columns values are not equal from each row in Sub1 and Sub2
If(intColcheck!= Subscriber.Columns.Count)
{
Console.WriteLine("Found the Unique Row from Subscriber1 ");
//Insert the logic add row into third data table.
}
}