Vba Excel宏:如果列匹配,则合并行

Vba Excel宏:如果列匹配,则合并行,vba,excel,Vba,Excel,我希望能够合并第一列中的值与之匹配的行,以便将非空白单元格的值合并为一行。例如: Mary Smith, A, [blank cell] Mary Smith, [blank cell], B Mary Smith, A, [blank cell] Mary Smith, [blank cell], B --> 我已尝试使用以下代码: Dim RowNum As Long, LastRow As Long Application.ScreenUpdating = False RowN

我希望能够合并第一列中的值与之匹配的行,以便将非空白单元格的值合并为一行。例如:

Mary Smith, A, [blank cell]

Mary Smith, [blank cell], B
Mary Smith, A, [blank cell]

Mary Smith, [blank cell], B
-->

我已尝试使用以下代码:

Dim RowNum As Long, LastRow As Long

Application.ScreenUpdating = False

RowNum = 4

LastRow = Cells.SpecialCells(xlCellTypeLastCell).Row

Range("A4", Cells(LastRow, 13)).Select

For Each Row In Selection

 With Cells

If Cells(RowNum, 1) = Cells(RowNum + 1, 1) Then

 Cells(RowNum + 1, 1).Copy Destination:=Cells(RowNum, 1)

 Cells(RowNum + 1, 2).Copy Destination:=Cells(RowNum, 2)

 Cells(RowNum + 1, 3).Copy Destination:=Cells(RowNum, 3)

Cells(RowNum + 1, 4).Copy Destination:=Cells(RowNum, 4)

Cells(RowNum + 1, 5).Copy Destination:=Cells(RowNum, 5)

Cells(RowNum + 1, 6).Copy Destination:=Cells(RowNum, 6)

 Cells(RowNum + 1, 7).Copy Destination:=Cells(RowNum, 7)

 Cells(RowNum + 1, 8).Copy Destination:=Cells(RowNum, 8)

 Cells(RowNum + 1, 9).Copy Destination:=Cells(RowNum, 9)

 Cells(RowNum + 1, 10).Copy Destination:=Cells(RowNum, 10)

Cells(RowNum + 1, 11).Copy Destination:=Cells(RowNum, 11)

 Cells(RowNum + 1, 12).Copy Destination:=Cells(RowNum, 12)

 Cells(RowNum + 1, 13).Copy Destination:=Cells(RowNum, 13)

Rows(RowNum + 1).EntireRow.Delete

End If

End With

RowNum = RowNum + 1

Next Row

Application.ScreenUpdating = True

'

End Sub
这在整合数据方面做得很好,因此第一列中只有唯一的值,但是,当复制行时,空白单元格的值会复制到填充的单元格上,这不是我想要的。例如,在上述数据上运行此宏将产生:

-->

如果您能深入了解我如何修改上述代码(或使用更优雅的代码),我们将不胜感激

试试下面的代码

Sub test()
    LastRow = Range("A" & Rows.Count).End(xlUp).Row
    For i = 4 To LastRow
        If ((Range("A" & i).Value = Range("A" & i + 1).Value) And (Range("B" & i).Value <> Range("B" & i + 1).Value) And ((Range("B" & i).Value = "") Or (Range("B" & i + 1).Value = "")) And (Range("C" & i).Value <> Range("C" & i + 1).Value) And ((Range("C" & i).Value = "") Or (Range("C" & i + 1).Value = ""))) Then
            If Range("B" & i).Value = "" Then
                Range("B" & i).Value = Range("B" & i + 1).Value
            ElseIf Range("B" & i + 1).Value = "" Then
                Range("B" & i + 1).Value = Range("B" & i).Value
            End If
            If Range("C" & i).Value = "" Then
                Range("C" & i).Value = Range("C" & i + 1).Value
            ElseIf Range("C" & i + 1).Value = "" Then
                Range("C" & i + 1).Value = Range("C" & i).Value
            End If
        End If
        Range("B" & i).EntireRow.Delete Shift:=(xlUp)
        LastRow = LastRow - 1
    Next i
End Sub
子测试()
LastRow=范围(“A”和Rows.Count).End(xlUp).Row
对于i=4到最后一行
如果((范围(“A”&i).Value=Range(“A”&i+1).Value)和((范围(“B”&i+1.Value”)和((范围(“B”&i.Value=”“)或(范围(“B”&i+1.Value=”“)和((范围(“C”&i.Value”)和((范围(“C”&i.Value=“”)或(范围(“C”&i+1.Value=“”)那么
如果范围(“B”&i).Value=”“,则
范围(“B”&i).值=范围(“B”&i+1).值
ElseIf范围(“B”&i+1).Value=”“然后
范围(“B”&i+1).值=范围(“B”&i).值
如果结束
如果范围(“C”&i).Value=”“,则
范围(“C”&i).值=范围(“C”&i+1).值
ElseIf范围(“C”&i+1).Value=”“然后
范围(“C”&i+1).值=范围(“C”&i).值
如果结束
如果结束
范围(“B”和i).EntireRow.Delete Shift:=(xlUp)
LastRow=LastRow-1
接下来我
端接头

这将很快完成:

Sub foo()
    Dim ws As Worksheet
    Dim lstrow As Long

    Set ws = Sheets("Sheet1") ' Change to your sheet

    With ws
        lstrow = .Range("A" & .Rows.Count).End(xlUp).Row
        With .Range("B4:M" & lstrow)
            .Offset(, 26).FormulaR1C1 = "=IFERROR(INDEX(R4C[-26]:R" & lstrow & "C[-26],MATCH(1,INDEX((R4C1:R" & lstrow & "C1 = RC1)*(R4C[-26]:R" & lstrow & "C[-26] <>""""),),0)),"""")"
            ws.Calculate
            .Value = .Offset(, 26).Value
            .Offset(, 26).ClearContents
        End With
        With .Range("A4:M" & lstrow)
            .Value = .Value
            .RemoveDuplicates 1, xlGuess
        End With
    End With

End Sub
Sub-foo()
将ws设置为工作表
一排一排的
将ws=Sheets(“Sheet1”)更改为您的工作表
与ws
lstrow=.Range(“A”&.Rows.Count).End(xlUp).Row
带.Range(“B4:M”和lstrow)
.Offset(,26).FormulaR1C1=“=IFERROR(索引(R4C[-26]:R“&lstrow&”C[-26)),匹配(1,索引((R4C1:R“&lstrow&”C1=RC1)*(R4C[-26]:R“&lstrow&“C[-26]”),0)),”
ws.Calculate
.Value=.Offset(,26).Value
.Offset(,26).ClearContents
以
带.Range(“A4:M”和lstrow)
.Value=.Value
.删除副本1,xl
以
以
端接头
它基本上使用公式:
=INDEX(B$4:B$4,MATCH(1,INDEX($A$4:$A$4=$A4)*(B$4:B$4“”),0))
来查找所有值。将这些公式放在空白列中,然后将数据复制回来并删除重复项

这将一次完成所有13列

它也不关心A列中的值重复了多少次。该列中可能有4个
Mary Smith
s。它将获取每列中的第一个值并使用它

之前:

之后:

这里是另一种方法。 创建一个人员对象。每个人员对象可以有多个属性(原始表中的非空列条目)

通过使用集合对象的Key属性,并使用名称(column1数据)作为键,我们可以检测重复项,而不必对原始数据进行排序。每个名称的属性数量仅受工作表大小的限制

其他信息见评论

插入一个类对象并重命名它
cPersonnel

下面是类和常规模块的代码

类模块 正则模
选项显式
次级人员
将wsSrc标注为工作表,wsRes标注为工作表,rRes标注为范围
Dim vSrc作为变型,vRes()作为变型
作为cPersonnel的Dim cP,作为集合的colP
调暗LastRow和LastCol一样长
我和我一样长,我和我一样长
'设置源和结果工作表、范围
设置wsSrc=工作表(“表1”)
设置wsRes=工作表(“表2”)
设置rRes=wsRes.Cells(1,1)
使用wsSrc.Cells
LastRow=.Find(what:=“*”,after:=.Cells(1,1),LookIn:=xlFormulas_
搜索顺序:=xlByRows,搜索方向:=xlPrevious)。行
LastCol=.Find(what:=“*”,after:=.Cells(1,1),LookIn:=xlformals_
searchorder:=xlByColumns,searchdirection:=xlPrevious).Column
以
'将源数据读入数组
与wsSrc
vSrc=范围(.Cells(1,1),.Cells(LastRow,LastCol))
以
'创建并收集人员对象
'源数据不需要排序
Set colP=新集合
出错时继续下一步
对于I=1到UBound(vSrc,1)
如果修剪(vSrc(I,1))”,则
设置cP=新CPERSONEL
与cP
.Name=vSrc(I,1)
对于J=2至UBound(vSrc,2)
如果修剪(vSrc(I,J))”“那么
.Attrib=微调(vSrc(I,J))
.ADDAttribS.Attrib
如果结束
下一个J
colP.Add cP、.Name
选择案例错误编号
案例457“重复名称”
呃,明白了
对于J=1到.AttribS.Count
colP(.Name).ADDAttribS.AttribS(J)
下一个J
案例为0
调试.打印错误号,错误说明
停止
结束选择
以
如果结束
接下来我
错误转到0
'创建结果数组
'列数
对于I=1到colP.Count
与colP(I)
J=IIf(J>.AttribS.Count,J,.AttribS.Count)
以
接下来我
ReDim vRes(0到冷却液计数,0到J)
'标题
vRes(0,0)=“名称”
对于J=1至UBound(vRes,2)
vRes(0,J)=“Attrib”&J
下一个J
'填充数据
对于I=1到colP.Count
与colP(I)
vRes(I,0)=.名称
对于J=1到.AttribS.Count
vRes(I,J)=.AttribS(J)
下一个J
以
接下来我
'清除旧数据并写入新数据
设置rRes=rRes。调整大小(UBound(vRes,1)+1,UBound(vRes,2)+1)
与rRes
.全部清除
.Value=vRes
带.行(1)
Sub test()
    LastRow = Range("A" & Rows.Count).End(xlUp).Row
    For i = 4 To LastRow
        If ((Range("A" & i).Value = Range("A" & i + 1).Value) And (Range("B" & i).Value <> Range("B" & i + 1).Value) And ((Range("B" & i).Value = "") Or (Range("B" & i + 1).Value = "")) And (Range("C" & i).Value <> Range("C" & i + 1).Value) And ((Range("C" & i).Value = "") Or (Range("C" & i + 1).Value = ""))) Then
            If Range("B" & i).Value = "" Then
                Range("B" & i).Value = Range("B" & i + 1).Value
            ElseIf Range("B" & i + 1).Value = "" Then
                Range("B" & i + 1).Value = Range("B" & i).Value
            End If
            If Range("C" & i).Value = "" Then
                Range("C" & i).Value = Range("C" & i + 1).Value
            ElseIf Range("C" & i + 1).Value = "" Then
                Range("C" & i + 1).Value = Range("C" & i).Value
            End If
        End If
        Range("B" & i).EntireRow.Delete Shift:=(xlUp)
        LastRow = LastRow - 1
    Next i
End Sub
Sub foo()
    Dim ws As Worksheet
    Dim lstrow As Long

    Set ws = Sheets("Sheet1") ' Change to your sheet

    With ws
        lstrow = .Range("A" & .Rows.Count).End(xlUp).Row
        With .Range("B4:M" & lstrow)
            .Offset(, 26).FormulaR1C1 = "=IFERROR(INDEX(R4C[-26]:R" & lstrow & "C[-26],MATCH(1,INDEX((R4C1:R" & lstrow & "C1 = RC1)*(R4C[-26]:R" & lstrow & "C[-26] <>""""),),0)),"""")"
            ws.Calculate
            .Value = .Offset(, 26).Value
            .Offset(, 26).ClearContents
        End With
        With .Range("A4:M" & lstrow)
            .Value = .Value
            .RemoveDuplicates 1, xlGuess
        End With
    End With

End Sub
Option Explicit
Private pName As String
Private pAttrib As String
Private pAttribs As Collection

Public Property Get Name() As String
    Name = pName
End Property
Public Property Let Name(Value As String)
    pName = Value
End Property

Public Property Get Attrib() As String
    Attrib = pAttrib
End Property
Public Property Let Attrib(Value As String)
    pAttrib = Value
End Property

Public Property Get AttribS() As Collection
    Set AttribS = pAttribs
End Property
Public Function ADDAttribS(Value As String)
    pAttribs.Add Value
End Function

Private Sub Class_Initialize()
    Set pAttribs = New Collection
End Sub
Option Explicit
Sub PersonnelAttribs()
    Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range
    Dim vSrc As Variant, vRes() As Variant
    Dim cP As cPersonnel, colP As Collection
    Dim LastRow As Long, LastCol As Long
    Dim I As Long, J As Long

'Set source and results worksheets, ranges
Set wsSrc = Worksheets("sheet1")
Set wsRes = Worksheets("sheet2")
    Set rRes = wsRes.Cells(1, 1)

With wsSrc.Cells
    LastRow = .Find(what:="*", after:=.Cells(1, 1), LookIn:=xlFormulas, _
        searchorder:=xlByRows, searchdirection:=xlPrevious).Row
    LastCol = .Find(what:="*", after:=.Cells(1, 1), LookIn:=xlFormulas, _
        searchorder:=xlByColumns, searchdirection:=xlPrevious).Column
End With

'Read source data into array
With wsSrc
    vSrc = Range(.Cells(1, 1), .Cells(LastRow, LastCol))
End With

'create and collect the Personnel objects
'Source data does not need to be sorted
Set colP = New Collection
On Error Resume Next
For I = 1 To UBound(vSrc, 1)
    If Trim(vSrc(I, 1)) <> "" Then
        Set cP = New cPersonnel
        With cP
            .Name = vSrc(I, 1)
            For J = 2 To UBound(vSrc, 2)
                If Trim(vSrc(I, J)) <> "" Then
                    .Attrib = Trim(vSrc(I, J))
                    .ADDAttribS .Attrib
                End If
            Next J
            colP.Add cP, .Name
            Select Case Err.Number
                Case 457 'duplicate name
                    Err.Clear
                    For J = 1 To .AttribS.Count
                        colP(.Name).ADDAttribS .AttribS(J)
                    Next J
                Case Is <> 0
                    Debug.Print Err.Number, Err.Description
                    Stop
            End Select
        End With
    End If
Next I
On Error GoTo 0

'Create results array
'Number of columns
For I = 1 To colP.Count
With colP(I)
    J = IIf(J > .AttribS.Count, J, .AttribS.Count)
End With
Next I

ReDim vRes(0 To colP.Count, 0 To J)

'Headers
vRes(0, 0) = "Name"
For J = 1 To UBound(vRes, 2)
    vRes(0, J) = "Attrib " & J
Next J

'Populate data
For I = 1 To colP.Count
With colP(I)
    vRes(I, 0) = .Name
    For J = 1 To .AttribS.Count
        vRes(I, J) = .AttribS(J)
    Next J
End With
Next I

'Clear old data and write new
Set rRes = rRes.Resize(UBound(vRes, 1) + 1, UBound(vRes, 2) + 1)
With rRes
    .EntireColumn.Clear
    .Value = vRes
    With .Rows(1)
        .Font.Bold = True
        .HorizontalAlignment = xlCenter
    End With
    .EntireColumn.AutoFit
End With   
End Sub