在列VBA中合并具有相似值的行

时间:2019-08-24 02:16:50

标签: excel vba

我在Stack Overflow上找到了一个代码,它合并了A列中具有相同值的行,但是我不能修改它的代码以合并A列中具有相似值的行。

例如:

enter image description here 代码运行后,合并或合并的行应该具有,但是它的作用是将A列中的每个值视为唯一值:

结果应为:101 102 12

请有人帮助我修改或共享一个代码,以合并列A中具有相似值的行。谢谢!

   Sub CombineRows()

    Dim Rng As Range, _
                    Dn As Range _
                    , N As Long _
                    , nRng As Range

    On Error Resume Next

    Set Rng = Range(Range("A2"), Range("A" & Rows.count).End(xlUp))
    With CreateObject("scripting.dictionary")
    .CompareMode = vbTextCompare

    For Each Dn In Rng
        If Not .Exists(Dn.Value) Then
            .Add Dn.Value, Dn
        Else
            If nRng Is Nothing Then Set nRng = _
            Dn Else Set nRng = Union(nRng, Dn)
            .Item(Dn.Value).Offset(, 2) = .Item(Dn.Value).Offset(, 2) + 
             Dn.Offset(, 2)
            .Item(Dn.Value).Offset(, 3) = .Item(Dn.Value).Offset(, 3) + 
             Dn.Offset(, 3)
            .Item(Dn.Value).Offset(, 4) = .Item(Dn.Value).Offset(, 4) + 
             Dn.Offset(, 4)


        End If
    Next
    If Not nRng Is Nothing Then nRng.EntireRow.Delete
    End With


    End Sub

@DecimalTurn的答案。我调整了字符串变量; Shortstring&Longsting从字符串中取出所有逗号。

Dim c1 As Range, c2 As Range
    For Each c1 In Rng

        Dim ShortString  As String
        ShortString = Replace(c1.Value2, ",", "")

        For Each c2 In Rng

            If c2.row > c1.row Then 'Because we sorted the rows, we only need to look at the row if it's a row below c1.

                Dim LongString  As String
                LongString = Replace(c2.Value2, ",", "")

                If InStr(LongString, ShortString) > 0 Then

                    'Add Combine similar lines
                    c1.Offset(, 2).Value2 = c1.Offset(, 2).Value2 + c2.Offset(, 2).Value2
                    c1.Offset(, 3).Value2 = c1.Offset(, 3).Value2 + c2.Offset(, 3).Value2
                    c1.Offset(, 4).Value2 = c1.Offset(, 4).Value2 + c2.Offset(, 4).Value2

                    'Delete current line since it has a similar value as the shorter one.
                    c2.EntireRow.Delete
                End If

            End If

        Next c2
    Next c1

1 个答案:

答案 0 :(得分:0)

查看两个strings是否“相似”的一种简单方法是测试一个字符串是否包含在另一个字符串中。为此,您可以使用函数Sub Fill() Dim JsonText As String Dim Parsed As Dictionary file_name = "YourFile.json" my_file = FreeFile() Open file_name For Input As my_file i = 1 While Not EOF(my_file) Line Input #my_file, text_line JsonText = JsonText + text_line i = i + 1 Wend Set Parsed = JsonConverter.ParseJson(JsonText) Dim ticker, third, v As Variant Dim dict2, dict3 As Variant Dim r, c, r2 As Integer r = 2 For Each ticker In Parsed.Keys() ' AAL Set dict2 = Parsed.Item(ticker) ActiveSheet.Cells(r, 1).Value = ticker ' set ticker on first line c = 2 For Each third In dict2.Keys() ' year ActiveSheet.Cells(1, c).Value = third Set dict3 = dict2.Item(third) r2 = r For Each v In dict3 ActiveSheet.Cells(r2, 1).Value = ticker ' repeat ticker on next lines ActiveSheet.Cells(r2, c).Value = v r2 = r2 + 1 Next v c = c + 1 Next third r = r2 Next ticker 'Sheets("example").Range(Cells(1, 1), Cells(Parsed("values").Count, 3)) = Values End Sub

以下是使用方法的示例:

InStr

为了在2行以上实现此功能,我们可以调整您提交的代码的标准值,并将其设置为代码的第一步。此步骤确保我们已经合并了A列中具有完全相同值的行。对于步骤2 ,我们需要按A列中的值的长度进行排序,以便我们可以轻松地循环在下一步。在第3步中,我们遍历该范围(双循环),并检查较短的A列值(c1)是否出现在其下方的任何单元格(c2)中。如果是,那么我们将这两行合并。

这是它的样子:

Sub TestInstr()

    Dim txt1 As String, txt2 As String
    txt1 = ActiveSheet.Range("A1")
    txt2 = ActiveSheet.Range("A2")

    Dim Substring As String, FullString As String

    If Len(txt1) <= Len(txt2) Then

        Substring = txt1
        FullString = txt2

    Else

        Substring = txt2
        FullString = txt1

    End If


    If InStr(FullString, Substring) > 0 Then

        'This code runs when the substring is included somewhere inside the full string

    Else

        'This code runs when the substring is not included anywhere inside the full string

    End If

End Sub

要进行测试,我使用下面的宏生成了数据并获得了预期的结果:

enter image description here

Sub CombineRows()

    Dim ws As Worksheet
    Set ws = ActiveSheet

    Dim Rng As Range
    Set Rng = ws.Range(ws.Range("A1"), ws.Range("A" & ws.Rows.Count).End(xlUp))

    Dim RangeValues As Object
    Set RangeValues = CreateObject("Scripting.Dictionary")
    RangeValues.CompareMode = vbTextCompare

    '1) Store unique values in dictionary and combine identical rows
    Dim c As Range
    For Each c In Rng

        If Not RangeValues.Exists(c.Value) Then

            RangeValues.Add c.Value2, c

        Else

            'Add Combine identical lines
            RangeValues.Item(c.Value).Offset(, 1).Value2 = RangeValues.Item(c.Value).Offset(, 1).Value2 + c.Offset(, 1).Value2
            RangeValues.Item(c.Value).Offset(, 2).Value2 = RangeValues.Item(c.Value).Offset(, 2).Value2 + c.Offset(, 2).Value2
            RangeValues.Item(c.Value).Offset(, 3).Value2 = RangeValues.Item(c.Value).Offset(, 3).Value2 + c.Offset(, 3).Value2

            'Delete current line since it has the same value as another existing one.
            c.EntireRow.Delete

        End If

    Next

    '2) Sort the range by shortest string length
    ws.Columns("A:A").Insert Shift:=xlToRight

    For Each c In Rng
        c.Offset(0, -1).Value2 = Len(c.Value2)
    Next c

    Dim TableRange As Range
    Const NbOfColumns As Long = 5
    Set Rng = ws.Range(ws.Range("A1"), ws.Range("A" & ws.Rows.Count).End(xlUp)) 'Reset
    Set TableRange = Rng.Resize(Rng.Rows.Count, NbOfColumns + 1)

    ws.Sort.SortFields.Clear
    ws.Sort.SortFields.Add2 Key:=TableRange.Columns(1) _
        , SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    With ws.Sort
        .SetRange TableRange
        .Header = xlGuess
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With

    ws.Columns("A:A").Delete Shift:=xlToLeft

    Set Rng = ws.Range(ws.Range("A1"), ws.Range("A" & ws.Rows.Count).End(xlUp)) 'Reset

    '3) Combine similar rows (ie. rows where the shortest value is included in the longest)
    Dim c1 As Range, c2 As Range
    For Each c1 In Rng

        Dim ShortString  As String
        ShortString = c1.Value2

        For Each c2 In Rng

            If c2.Row > c1.Row Then 'Because we sorted the rows, we only need to look at the row if it's under c1.

                Dim LongString  As String
                LongString = c2.Value2

                If InStr(LongString, ShortString) > 0 Then

                    'Add Combine similar lines
                    c1.Offset(, 1).Value2 = c1.Offset(, 1).Value2 + c2.Offset(, 1).Value2
                    c1.Offset(, 2).Value2 = c1.Offset(, 2).Value2 + c2.Offset(, 2).Value2
                    c1.Offset(, 3).Value2 = c1.Offset(, 3).Value2 + c2.Offset(, 3).Value2

                    'Delete current line since it has a similar value as the shorter one.
                    c2.EntireRow.Delete
                End If

            End If

        Next c2
    Next c1

End Sub