Excel重复行

Excel重复行,excel,vba,Excel,Vba,我有很多员工在一份名单上,上面写着他们上过哪些课程。A列是他们的客户ID,M列是他们完成的课程 如果每个ID都有重复的课程记录,我如何删除一行,因为有些员工会使用相同的课程名称。使用Excel中的“删除重复项”功能,只需突出显示要消除重复值的两列即可。下面的快速示例: 然后在对话框中选择要检查重复值的两列(确保取消选中所有不相关的列) 我的示例输出: 使用Excel中的“删除重复项”功能,只需突出显示要消除重复值的两列。下面的快速示例: 然后在对话框中选择要检查重复值的两列(确保取消选中所有

我有很多员工在一份名单上,上面写着他们上过哪些课程。A列是他们的客户ID,M列是他们完成的课程


如果每个ID都有重复的课程记录,我如何删除一行,因为有些员工会使用相同的课程名称。

使用Excel中的“删除重复项”功能,只需突出显示要消除重复值的两列即可。下面的快速示例:

然后在对话框中选择要检查重复值的两列(确保取消选中所有不相关的列)

我的示例输出:


使用Excel中的“删除重复项”功能,只需突出显示要消除重复值的两列。下面的快速示例:

然后在对话框中选择要检查重复值的两列(确保取消选中所有不相关的列)

我的示例输出:

删除重复行,即隐藏或删除
  • 第一个子项显示如何使用第二个子项,即主子项(
    removeDuplicateRows
  • 其余的接头被称为主接头(也是必要的)
  • 只有在完成测试后,才能从隐藏变为删除
代码

Option Explicit

Sub testRemoveDuplicateRows()
    
    Const wsName As String = "Sheet1"
    Const LastRowColumnID As Variant = "A" ' e.g. 1 or "A"
    Const FirstRow As Long = 2
    Dim ColumnIDs As Variant: ColumnIDs = Array(1, "M")
    Dim wb As Workbook: Set wb = ThisWorkbook
    
    Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
    
    ' Hide duplicate rows.
    removeDuplicateRows ws, ColumnIDs, LastRowColumnID, FirstRow, True

    ' Delete duplicate rows.
    'removeDuplicateRows ws, ColumnIDs, LastRowColumnID, FirstRow

End Sub

Sub removeDuplicateRows(Sheet As Worksheet, _
                        ColumnIDs As Variant, _
                        Optional LastRowColumnID As Variant = 1, _
                        Optional FirstRow As Long = 1, _
                        Optional hideOnly As Boolean = False)

    ' Write values of columns to jagged array.
    Dim Cols As Variant
    getColumns Cols, Sheet, ColumnIDs, LastRowColumnID, FirstRow
    
    ' Join values of arrays in jagged array.
    Dim Data As Variant: joinColumns Data, Cols
    
    ' Write duplicate row numbers to array.
    Dim RowOffset As Long: RowOffset = FirstRow - 1 ' 1 = ubound(Data)
    Dim DupeRows As Variant
    collectDuplicateRows DupeRows, Data, RowOffset
    
    ' Hide or delete duplicate rows.
    If hideOnly Then
        hideRows Sheet, DupeRows
    Else
        deleteRows Sheet, DupeRows
    End If
      
End Sub

Sub getColumns(ByRef Data As Variant, _
               Sheet As Worksheet, _
               ColumnIDs As Variant, _
               Optional LastRowColumnID As Variant = 1, _
               Optional FirstRow As Long = 1)
    
    Dim ubc As Long: ubc = UBound(ColumnIDs)
    If ubc = -1 Then Exit Sub
    
    Dim rng As Range: getColumnRange rng, Sheet, LastRowColumnID, FirstRow
    If rng Is Nothing Then Exit Sub
    
    ReDim Data(ubc): getColumnFromColumnRange Data(0), rng
    
    If ubc > 0 Then GoSub getRemainingColumns
     
    Exit Sub

getRemainingColumns:
    Dim j As Long
    For j = 1 To ubc
        getColumnFromColumnRange Data(j), _
          rng.Offset(, Sheet.Columns(ColumnIDs(j)).Column - rng.Column)
    Next j
    Return

End Sub

Sub getColumnRange(ByRef ColumnRange As Range, _
                   Sheet As Worksheet, _
                   Optional ColumnID As Variant = 1, _
                   Optional FirstRow As Long = 1)
    
    Set ColumnRange = Nothing
    
    Dim rng As Range
    Set rng = Sheet.Columns(ColumnID).Find("*", , xlValues, , , xlPrevious)
    
    If rng Is Nothing Then Exit Sub
    If rng.Row < FirstRow Then Exit Sub
    
    Set ColumnRange = Sheet.Range(Sheet.Cells(FirstRow, ColumnID), rng)

End Sub
                    
Sub getColumnFromColumnRange(ByRef Data As Variant, _
                             ColumnRange As Range)
    If ColumnRange Is Nothing Then Exit Sub
    If ColumnRange.Cells.Count > 1 Then
        Data = ColumnRange.Value
    Else
        ReDim Data(1 To 1, 1 To 1): Data(1, 1) = ColumnRange.Value
    End If
End Sub
                             
Sub joinColumns(ByRef Data As Variant, _
                ColumnsArray As Variant, _
                Optional Delimiter As String = "|||")
    
    Data = ColumnsArray(0)
    If UBound(ColumnsArray) = 0 Then Exit Sub
    
    Dim ubr As Long: ubr = UBound(Data)
    Dim j As Long, i As Long
    For j = 1 To UBound(ColumnsArray)
        For i = 1 To ubr
            Data(i, 1) = Data(i, 1) & Delimiter & ColumnsArray(j)(i, 1)
        Next i
    Next j
    
End Sub
                
Sub collectDuplicateRows(ByRef DupeRows As Variant, _
                         Data As Variant, _
                         Optional RowOffset As Long = 0, _
                         Optional DupeRowsFirstIndex As Long = 0)
    
    Dim ub As Long: ub = UBound(Data)
    If ub < 2 Then Exit Sub
    
    Dim i As Long, k As Long, m As Long: m = DupeRowsFirstIndex - 1
    ReDim DupeRows(DupeRowsFirstIndex To ub + DupeRowsFirstIndex - 2)
    
    For i = 1 To ub - 1
        For k = i + 1 To ub
            If Data(k, 1) = Data(i, 1) Then
                m = m + 1
                DupeRows(m) = k + RowOffset
                Exit For
            End If
        Next k
    Next i
    
    If m > DupeRowsFirstIndex - 1 Then
        ReDim Preserve DupeRows(DupeRowsFirstIndex To m)
    Else
        DupeRows = Empty
    End If
    
End Sub

Sub deleteRows(Sheet As Worksheet, _
               RowNumbers As Variant)
    
    Dim rng As Range: Set rng = Sheet.Rows(RowNumbers(LBound(RowNumbers)))
    If UBound(RowNumbers) > LBound(RowNumbers) Then GoSub collectRemainingRows
    
    If Not rng Is Nothing Then rng.EntireRow.Delete
    
    Exit Sub
    
collectRemainingRows:
    Dim j As Long
    For j = LBound(RowNumbers) + 1 To UBound(RowNumbers)
        Set rng = Union(rng, Sheet.Rows(RowNumbers(j)))
    Next j
    Return
    
End Sub

Sub hideRows(Sheet As Worksheet, _
             RowNumbers As Variant)
    
    Dim rng As Range: Set rng = Sheet.Rows(RowNumbers(LBound(RowNumbers)))
    If UBound(RowNumbers) > LBound(RowNumbers) Then GoSub collectRemainingRows
    
    If Not rng Is Nothing Then rng.EntireRow.Hidden = True
    
    Exit Sub
    
collectRemainingRows:
    Dim j As Long
    For j = LBound(RowNumbers) + 1 To UBound(RowNumbers)
        Set rng = Union(rng, Sheet.Rows(RowNumbers(j)))
    Next j
    Return
    
End Sub
选项显式
子TestRemovedUpplicateRows()
Const wsName As String=“Sheet1”
Const LastRowColumnID作为Variant=“A”例如1或“A”
常量第一行长度=2
Dim ColumnId作为变量:ColumnId=Array(1,“M”)
将wb设置为工作簿:设置wb=ThisWorkbook
将ws设置为工作表:设置ws=wb.Worksheets(wsName)
'隐藏重复行。
RemovedUpplicateRows ws,ColumnId,LastRowColumnID,FirstRow,True
'删除重复的行。
'RemovedUpplicateRows ws,ColumnId,LastRowColumnID,FirstRow
端接头
子移除的重复行(作为工作表的工作表_
柱状体作为变体_
可选LastRowColumnID作为变量=1_
可选的第一行,长度为1_
可选隐藏为布尔值=False)
'将列的值写入锯齿数组。
Dim Cols作为变体
getColumns Cols、Sheet、ColumnId、LastRowColumnID、FirstRow
'在交错数组中连接数组的值。
Dim数据作为变量:joinColumns数据,Cols
'将重复的行号写入数组。
按长度调整行偏移量:行偏移量=第一行-1'1=ubound(数据)
Dim Duperow作为变体
收集重复行DupeRows、数据、行偏移量
'隐藏或删除重复行。
如果很可怕的话
隐藏工作表
其他的
删除行表,DupeRows
如果结束
端接头
子getColumns(ByRef数据作为变量_
工作表作为工作表_
柱状体作为变体_
可选LastRowColumnID作为变量=1_
可选的第一行(长=1)
长度为的尺寸ubc:ubc=UBound(列ID)
如果ubc=-1,则退出Sub
Dim rng As Range:getColumnRange rng,Sheet,LastRowColumnID,FirstRow
如果rng为空,则退出Sub
ReDim数据(ubc):getColumnFromColumnRange数据(0),rng
如果ubc>0,则GoSub getRemainingColumns
出口接头
getRemainingColumns:
Dim j尽可能长
对于j=1至ubc
getColumnFromColumnRange数据(j)_
rng.Offset(,表列(列ID(j)).Column-rng.Column)
下一个j
返回
端接头
子getColumnRange(ByRef ColumnRange作为范围_
工作表作为工作表_
可选的ColumnID变量=1_
可选的第一行(长=1)
设置ColumnRange=Nothing
变暗rng As范围
Set rng=Sheet.Columns(ColumnID).Find(“*”,xlValues,,xlPrevious)
如果rng为空,则退出Sub
如果rng.Row<第一行,则退出Sub
Set ColumnRange=Sheet.Range(Sheet.Cells(第一行,ColumnID),rng)
端接头
Sub getColumnFromColumnRange(ByRef数据作为变量_
列范围作为范围)
如果ColumnRange为Nothing,则退出Sub
如果ColumnRange.Cells.Count>1,则
Data=ColumnRange.Value
其他的
ReDim数据(1到1,1到1):数据(1,1)=ColumnRange.Value
如果结束
端接头
子列(ByRef数据作为变量_
柱状体作为变体_
可选分隔符为String=“| | |”)
数据=列数组(0)
如果UBound(ColumnsArray)=0,则退出Sub
尺寸ubr长度:ubr=UBound(数据)
我和j一样长,我也一样长
对于j=1到UBound(ColumnsArray)
对于i=1至ubr
数据(i,1)=数据(i,1)&定界符和列数组(j)(i,1)
接下来我
下一个j
端接头
子集合重复行(ByRef DupeRows作为变量_
数据作为变量_
可选行偏移量,长度为0_
可选的DupeRowsFirstIndex(长度=0)
长度为的尺寸ub:ub=UBound(数据)
如果ub<2,则退出Sub
尺寸i等于长,k等于长,m等于长:m=DupeRowsFirstIndex-1
ReDim DupeRows(DupeRowsFirstIndex到ub+DupeRowsFirstIndex-2)
对于i=1到ub-1
对于k=i+1至ub
如果数据(k,1)=数据(i,1),则
m=m+1
DupeRows(m)=k+行偏移
退出
如果结束
下一个k
接下来我
如果m>DupeRowsFirstIndex-1,则
ReDim保留DupeRows(DupeRowsFirstIndex到m)
其他的
DupeRows=空
如果结束
端接头
子删除行(作为工作表的工作表_
行数(作为变量)
Dim rng As Range:设置rng=Sheet.Rows(行编号(LBound(行编号)))
如果UBound(行编号)>LBound(行编号),则GoSub collectRemainingRows
如果Not rng为Nothing,则rng.EntireRow.Delete
出口接头
收藏品