The code works on a single column in a DataGridView. A ComboBox list each column name in the DataGridView which is used to get duplicates.
The code requires a DataGridView with three columns (note form load event populates the rows).
Not sure of how much will make sense or not but as the image below shows it works.
Hope that helps.
Form code
Code:
Public Class frmMainForm
Private Sub cmdRemoveDupRows_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdRemoveDupRows.Click
Dim Items = (From T In DataGridView1.Rows.Cast(Of DataGridViewRow)() Select CStr(T.Cells(ComboBox1.Text).Value)).ToArray
Dim Items1 = Items.ListDuplicates
#If KSG_SHOW Then
' for debugging only, will display to IDE output window if KSG_SHOW is defined
If Items1.Count > 0 Then
For Each Ele In Items1
For row As Integer = 0 To Ele.List.Count - 1
Console.WriteLine("[{0}] [{1}]", Ele.Item, Ele.List(row))
Next
Next
End If
Console.WriteLine()
#End If
' Distinct list of dups from above
Dim noduplicates = Items1.Distinct(New DuplicateItemComparer)
' Used in MyRows LINQ statement which collects only DataGridView rows that are dups
Dim GetRidOfTheseRowsList As New List(Of Integer)
For Each item In noduplicates
GetRidOfTheseRowsList.Add(item.List(0))
Next
Dim MyRows = (From T In DataGridView1.Rows.Cast(Of DataGridViewRow)() Where GetRidOfTheseRowsList.Contains(T.Index)).ToList
If MyRows.Count > 0 Then
If My.Dialogs.Question("Remove rows?") Then
For Each row In MyRows
DataGridView1.Rows.Remove(row)
Next
End If
Else
My.Dialogs.InformationDialog("No duplicates for column " & ComboBox1.Text)
End If
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DataGridView1.Rows.Add(New Object() {"1", "A", "AAA"})
DataGridView1.Rows.Add(New Object() {"9", "B", "BBB"})
DataGridView1.Rows.Add(New Object() {"1", "C", "CCC"})
DataGridView1.Rows.Add(New Object() {"2", "D", "DDD"})
DataGridView1.Rows.Add(New Object() {"2", "E", "EEE"})
ComboBox1.DataSource = (From T In DataGridView1.Columns.Cast(Of DataGridViewColumn)() Select T.Name).ToList
ActiveControl = cmdRemoveDupRows
End Sub
End Class
Add the following file DuplicateItem.vb
Code:
Public Class DuplicateItem
Public Property Item As String
Public Property List As New List(Of Int32)
Public Sub New()
End Sub
Public Overrides Function ToString() As String
Return String.Join(",", List.ToArray)
End Function
End Class
Public Class DuplicateItem1
Public Property Value As String
Public Property Index As String
Public Sub New()
End Sub
End Class
Public Class DuplicateItemComparer
Implements IEqualityComparer(Of DuplicateItem)
Public Function Equals1(ByVal x As DuplicateItem, ByVal y As DuplicateItem) As Boolean _
Implements IEqualityComparer(Of DuplicateItem).Equals
' Check whether the compared objects reference the same data.
If x Is y Then Return True
'Check whether any of the compared objects is null.
If x Is Nothing OrElse y Is Nothing Then Return False
' Check whether the items' properties are equal.
Return (x.Item = y.Item)
End Function
Public Function GetHashCode1(ByVal Item As DuplicateItem) As Integer Implements IEqualityComparer(Of DuplicateItem).GetHashCode
' Check whether the object is null.
If Item Is Nothing Then Return 0
' Get hash code for the item field if it is not null.
Dim hashForItem = If(Item.Item Is Nothing, 0, Item.Item.GetHashCode())
' Calculate the hash code for the item.
Return hashForItem
End Function
End Class
Add the following file DuplicateListerCode.vb
Code:
Module DuplicateListerCode
<System.Diagnostics.DebuggerStepThrough()> _
<System.Runtime.CompilerServices.Extension()> _
Public Function ListDuplicates(ByVal sender As String()) As List(Of DuplicateItem)
Dim Result As New List(Of DuplicateItem)
Dim q = From value In sender.Select(Function(v, index) New With {.value = v.ToUpper, .index = index}) _
Group By value.value Into Group _
Where Group.Count > 1
For Each item In q
Dim LineList As New List(Of Int32)
For Each item2 In item.Group
LineList.Add(item2.index)
Next
Result.Add(New DuplicateItem With {.Item = item.value, .List = LineList})
Next
Return Result
End Function
End Module
Add the following file MyDialogs.vb
Code:
Namespace My
''' <summary>
''' Contains wrappers for common dialog operations where the intent is to keep
''' method based and easy to maintain.
''' </summary>
''' <remarks></remarks>
<Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Never)> _
Partial Friend Class _Dialogs
''' <summary>
''' Defaults to Tilde, used for breaking lines in dialogs
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property LineBreakChar As String = "~"
Private Function CreateLineBreaks(ByVal Text As String) As String
Return Text.Replace(LineBreakChar, Environment.NewLine)
End Function
Public Function Question(ByVal Text As String) As Boolean
Return _
(
MessageBox.Show(CreateLineBreaks(Text),
My.Application.Info.Title,
MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2) = MsgBoxResult.Yes)
End Function
''' <summary>
''' Shows text in dialog with information icon
''' </summary>
''' <param name="Text">Message to display</param>
''' <remarks></remarks>
Public Sub InformationDialog(ByVal Text As String)
MessageBox.Show(Text, My.Application.Info.Title, MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
End Class
<Global.Microsoft.VisualBasic.HideModuleName()> _
Friend Module KSG_Dialogs
Private instance As New ThreadSafeObjectProvider(Of _Dialogs)
ReadOnly Property Dialogs() As _Dialogs
Get
Return instance.GetInstance()
End Get
End Property
End Module
End Namespace