VBA – 查找并比较多个列中的数值

huangapple go评论233阅读模式
英文:

VBA - Find and compare values in multiple columns

问题

Sub CheckSame()

Dim i As Integer
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row


For i = 3 To lastRow
    If Cells(i, 13) = Cells(i - 1, 13) Then
        If Cells(i, 31) = Cells(i - 1, 31) And Cells(i, 32) = Cells(i - 1, 32) And Cells(i, 33) = Cells(i - 1, 33) And Cells(i, 34) = Cells(i - 1, 34) Then
            Cells(i, 36) = "Same"
        ElseIf Cells(i, 32) = Cells(i - 1, 32) And Cells(i, 33) = Cells(i - 1, 33) And Cells(i, 34) = Cells(i - 1, 34) Then
            Cells(i, 36) = "Name"
        ElseIf Cells(i, 31) = Cells(i - 1, 31) And Cells(i, 33) = Cells(i - 1, 33) And Cells(i, 34) = Cells(i - 1, 34) Then
            Cells(i, 36) = "Date"
        ElseIf Cells(i, 31) = Cells(i - 1, 31) And Cells(i, 32) = Cells(i - 1, 32) And Cells(i, 34) = Cells(i - 1, 34) Then
            Cells(i, 36) = "Active"
        ElseIf Cells(i, 31) = Cells(i - 1, 31) And Cells(i, 32) = Cells(i - 1, 32) And Cells(i, 33) = Cells(i - 1, 33) Then
            Cells(i, 36) = "Dept"
        End If
    End If
Next i
End Sub
英文:

Below is a table with a mock up of the data I have and what I need returned in the last column (AJ). What I am trying to do is look though all rows that have the same value in Column M and then compare the values in the rest of the columns noted below. Return same is all the values are the same, return the name(s) of the column(s) if something is different. I have tried starting for each but have two problems 1) its only comparing to previous row, not sets of rows with same value in column M, 2) I can only figure out how to identify on difference, not multiple. Any help is appreciated

Col M Col AE (Name) Col AF (Date) Col AG (Active) Col AH (Dept) Col AJ (What I want Returned)
A1234 Campaign 1 Jan 20,2022 1 Marketing Same
A1234 Campaign 1 Jan 20,2022 1 Marketing Same
A1234 Campaign 1 Jan 20,2022 1 Marketing Same
A4321 Campaign 2 Feb 20,2022 1 Marketing Date
A4321 Campaign 2 Mar 20,2022 1 Marketing Date
A4321 Campaign 2 Feb 20,2022 1 Marketing Date
A4321 Campaign 2 Feb 20,2022 1 Marketing Date
A2222 Campaign 3 Apr 20,2022 1 Marketing Name, Active
A2222 Campaign 3 Apr 20,2022 2 Marketing Name, Active
A2222 Campaign 33 Apr 20,2022 1 Marketing Name, Active
A2222 Campaign 3 Apr 20,2022 1 Marketing Name, Active

'''

Sub CheckSame()

Dim i As Integer
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row


For i = 3 To lastRow
    If Cells(i, 13) = Cells(i - 1, 13) Then
        If Cells(i, 31) = Cells(i - 1, 31) And Cells(i, 32) = Cells(i - 1, 32) And Cells(i, 33) = Cells(i - 1, 33) And Cells(i, 34) = Cells(i - 1, 34) Then
            Cells(i, 36) = "Same"
        ElseIf Cells(i, 32) = Cells(i - 1, 32) And Cells(i, 33) = Cells(i - 1, 33) And Cells(i, 34) = Cells(i - 1, 34) Then
            Cells(i, 36) = "Name"
        ElseIf Cells(i, 31) = Cells(i - 1, 31) And Cells(i, 33) = Cells(i - 1, 33) And Cells(i, 34) = Cells(i - 1, 34) Then
            Cells(i, 36) = "Date"
        ElseIf Cells(i, 31) = Cells(i - 1, 31) And Cells(i, 32) = Cells(i - 1, 32) And Cells(i, 34) = Cells(i - 1, 34) Then
            Cells(i, 36) = "Active"
        ElseIf Cells(i, 31) = Cells(i - 1, 31) And Cells(i, 32) = Cells(i - 1, 32) And Cells(i, 33) = Cells(i - 1, 33) Then
            Cells(i, 36) = "Dept"
        End If
    End If
Next i
End Sub

'''

答案1

得分: 2

以下是你要翻译的内容:

Option Explicit
Const SHOWPC = True

Sub CompareCols()

   Const COL_ID = "M"
   Const COL_NAME = "AE"
   Const COL_RESULT = "AJ"

   Dim ws As Worksheet, lastrow As Long, i As Long, j As Long
   Dim arDict, arCol, v, n As Long, msg As String
   arCol = Array("Name", "Date", "Active", "Dept")
   
   ReDim arDict(UBound(arCol)) As Object
   For i = 0 To UBound(arDict)
      Set arDict(i) = CreateObject("Scripting.Dictionary")
   Next
   
   Set ws = ThisWorkbook.Sheets("Sheet1")
   With ws
      lastrow = .Cells(.Rows.Count, COL_ID).End(xlUp).Row
      For i = 2 To lastrow
         For j = 0 To 3
            v = .Cells(i, "AE").Offset(, j)
            arDict(j)(v) = arDict(j)(v) + 1 ' count of this value
         Next
         n = n + 1
         
         ' is this last in group
         If .Cells(i + 1, COL_ID) <> .Cells(i, COL_ID) Then
             .Cells(i - n + 1, COL_RESULT).Resize(n, 5) = CompareRows(arDict, arCol)
             n = 0
         End If
      Next
   End With
   
   MsgBox lastrow - 1 & " rows scanned", vbInformation
End Sub

Function CompareRows(ByRef arDict, arCol) As Variant
     
    Dim v, s As String, sep As String, pc As String
    Dim n As Long, i As Long, tot As Long, m As Long
     
    n = UBound(arCol) ' cols to check
    Dim arCount: ReDim arCount(n) As Long
    Dim arResult: ReDim arResult(1 To 1, 1 To n + 2)
     
    ' check each column
    For i = 0 To n
        tot = 0
        For Each v In arDict(i).Keys
            m = arDict(i)(v) 'count of value
            tot = tot + m
             ' take v with most entries
            If m > arCount(i) Then
                arCount(i) = m
                arResult(1, i + 2) = v
            End If
        Next
         ' add pcent
        If SHOWPC Then
            pc = Format(arCount(i) / tot, " (0%)")
            arResult(1, i + 2) = arResult(1, i + 2) & pc
        End If
     
        If arDict(i).Count > 1 Then
            s = s & sep & arCol(i)
            sep = ","
        End If
        arDict(i).RemoveAll ' clear dictionary
     Next
     If s = "" Then s = "Same"
     arResult(1, 1) = s
     CompareRows = arResult
     
End Function

希望这有帮助!如果有任何其他问题,请随时提问。

英文:

In principle use 4 dictionaries (1 for each column) to count the number of times a value appears in a group of records.

Option Explicit
Const SHOWPC = True

Sub CompareCols()

   Const COL_ID = &quot;M&quot;
   Const COL_NAME = &quot;AE&quot;
   Const COL_RESULT = &quot;AJ&quot;

   Dim ws As Worksheet, lastrow As Long, i As Long, j As Long
   Dim arDict, arCol, v, n As Long, msg As String
   arCol = Array(&quot;Name&quot;, &quot;Date&quot;, &quot;Active&quot;, &quot;Dept&quot;)
   
   ReDim arDict(UBound(arCol)) As Object
   For i = 0 To UBound(arDict)
      Set arDict(i) = CreateObject(&quot;Scripting.DIctionary&quot;)
   Next
   
   Set ws = ThisWorkbook.Sheets(&quot;Sheet1&quot;)
   With ws
      lastrow = .Cells(.Rows.Count, COL_ID).End(xlUp).Row
      For i = 2 To lastrow
         For j = 0 To 3
            v = .Cells(i, &quot;AE&quot;).Offset(, j)
            arDict(j)(v) = arDict(j)(v) + 1 &#39; count of this value
         Next
         n = n + 1
         
         &#39; is this last in group
         If .Cells(i + 1, COL_ID) &lt;&gt; .Cells(i, COL_ID) Then
             .Cells(i - n + 1, COL_RESULT).Resize(n, 5) = CompareRows(arDict, arCol)
             n = 0
         End If
      Next
   End With
   
   MsgBox lastrow - 1 &amp; &quot; rows scanned&quot;, vbInformation
End Sub

Function CompareRows(ByRef arDict, arCol) As Variant
     
    Dim v, s As String, sep As String, pc As String
    Dim n As Long, i As Long, tot As Long, m As Long
     
    n = UBound(arCol) &#39; cols to check
    Dim arCount: ReDim arCount(n) As Long
    Dim arResult: ReDim arResult(1 To 1, 1 To n + 2)
     
    &#39; check each column
    For i = 0 To n
        tot = 0
        For Each v In arDict(i).keys
            m = arDict(i)(v) &#39;count of value
            tot = tot + m
             &#39; take v with most entries
            If m &gt; arCount(i) Then
                arCount(i) = m
                arResult(1, i + 2) = v
            End If
        Next
         &#39; add pcent
        If SHOWPC Then
            pc = Format(arCount(i) / tot, &quot; (0%)&quot;)
            arResult(1, i + 2) = arResult(1, i + 2) &amp; pc
        End If
     
        If arDict(i).Count &gt; 1 Then
            s = s &amp; sep &amp; arCol(i)
            sep = &quot;,&quot;
        End If
        arDict(i).RemoveAll &#39; clear dictionary
     Next
     If s = &quot;&quot; Then s = &quot;Same&quot;
     arResult(1, 1) = s
     CompareRows = arResult
     
End Function

</details>



# 答案2
**得分**: 0

以下是代码部分的翻译:

```vb
    Option Explicit

    Sub FlagUniques()

        ' 定义常量。
        Const WS_NAME As String = "Sheet1"
        Const UNIQUE_COL As String = "M"
        Const RESULT_COL As String = "AJ"
        Const TITLES_LIST As String = "Name,Date,Active,Dept"
        Const TITLE_DELiMITER As String = ","
        Const DUPE_STRING As String = "Same"
        Const UNIQUE_STRING As String = "Unique"
        Const INVALID_STRING As String = "Invalid"
        Const RESULT_DELIMITER As String = ", "

        ' 引用工作簿。
        Dim wb As Workbook: Set wb = ThisWorkbook ' 包含此代码的工作簿

        ' 引用工作表。
        Dim ws As Worksheet: Set ws = wb.Sheets(WS_NAME)
        Dim rg As Range: Set rg = ws.Range("A1").CurrentRegion ' 包含标题
        Dim hrg As Range: Set hrg = rg.Rows(1) ' 标题
        Dim rCount As Long: rCount = rg.Rows.Count - 1 ' 没有标题
        Set rg = rg.Resize(rCount).Offset(1) ' 没有标题

        ' 将唯一列的值写入数组(2D 基于一的数组)。
        Dim uData(): uData = rg.Columns(UNIQUE_COL).Value

        ' 将标题从列表中拆分为数组(1D 基于零的数组)。
        Dim Titles() As String: Titles = Split(TITLES_LIST, TITLE_DELiMITER)
        ' 将标题的索引匹配到数组中(1D 基于一的数组)。
        Dim tColIndexes(): tColIndexes = Application.Match(Titles, hrg, 0)

        ' 将标题列的值写入一个交错数组
        ' (1D 基于一的数组,包含基于一的2D 单列数组)。

        Dim tCount As Long: tCount = UBound(tColIndexes)
        Dim tJag(): ReDim tJag(1 To tCount)

        Dim t As Long

        For t = 1 To tCount
            tJag(t) = rg.Columns(tColIndexes(t)).Value
        Next t

        ' 将唯一数组中的唯一值写入字典的“键”,
        ' 并将它们的行写入由每个相关“项”持有的集合中。

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

        Dim sKey, r As Long, IsFound As Boolean

        For r = 1 To rCount
            sKey = uData(r, 1)
            ' 排除错误值和空白。
            If Not IsError(sKey) Then
                If Len(CStr(sKey)) > 0 Then IsFound = True
            End If
            ' 写入。
            If IsFound Then
                If Not dict.Exists(sKey) Then Set dict(sKey) = New Collection
                dict(sKey).Add r
                IsFound = False ' 为下一次迭代重置
            Else
                uData(r, 1) = INVALID_STRING
            End If
        Next r

        ' 循环遍历字典的“键”,遍历交错数组的列,
        ' 并遍历集合中的行,并将所需的结果写入唯一数组。

        Dim rLen As Long: rLen = Len(RESULT_DELIMITER)

        Dim Item, tVal, fr As Long, c As Long, cCount As Long, Result As String

        For Each sKey In dict.Keys
            cCount = dict(sKey).Count
            fr = dict(sKey)(1)
            If cCount = 1 Then
                uData(fr, 1) = UNIQUE_STRING
            Else
                For t = 1 To tCount
                    tVal = tJag(t)(fr, 1)
                    For c = 2 To cCount
                        r = dict(sKey)(c)
                        If tJag(t)(r, 1) <> tVal Then Exit For
                    Next c
                    If c <= cCount Then
                        Result = Result & Titles(t - 1) & RESULT_DELIMITER
                    End If
                    Debug.Print t, tVal, c, Result
                Next t
                If Len(Result) = 0 Then
                    Result = DUPE_STRING
                Else
                    Result = Left(Result, Len(Result) - rLen)
                End If
                For c = 1 To cCount
                    uData(dict(sKey)(c), 1) = Result
                Next c
                Result = vbNullString ' 为下一次迭代重置
            End If
        Next sKey

        ' 将唯一数组中的值写入目标列。
        Dim drg As Range: Set drg = rg.Columns(RESULT_COL)
        drg.Value = uData

        ' 通知。
        MsgBox "唯一值已标记。", vbInformation

    End Sub
```

<details>
<summary>英文:</summary>

Flag Unique Values
-

[![enter image description here][1]][1]

&lt;!-- language: lang-vb --&gt;

    Option Explicit
    
    Sub FlagUniques()
        
        &#39; Define constants.
        Const WS_NAME As String = &quot;Sheet1&quot;
        Const UNIQUE_COL As String = &quot;M&quot;
        Const RESULT_COL As String = &quot;AJ&quot;
        Const TITLES_LIST As String = &quot;Name,Date,Active,Dept&quot;
        Const TITLE_DELiMITER As String = &quot;,&quot;
        Const DUPE_STRING As String = &quot;Same&quot;
        Const UNIQUE_STRING As String = &quot;Unique&quot;
        Const INVALID_STRING As String = &quot;Invalid&quot;
        Const RESULT_DELIMITER As String = &quot;, &quot;
        
        &#39; Reference the workbook.
        Dim wb As Workbook: Set wb = ThisWorkbook &#39; workbook containing this code
        
        &#39; Reference the range.
        Dim ws As Worksheet: Set ws = wb.Sheets(WS_NAME)
        Dim rg As Range: Set rg = ws.Range(&quot;A1&quot;).CurrentRegion &#39; has headers
        Dim hrg As Range: Set hrg = rg.Rows(1) &#39; header
        Dim rCount As Long: rCount = rg.Rows.Count - 1 &#39; no headers
        Set rg = rg.Resize(rCount).Offset(1) &#39; no headers
        
        &#39; Write the values from the unique column to an array (2D one-based).
        Dim uData(): uData = rg.Columns(UNIQUE_COL).Value
        
        &#39; Split the titles from the list into an array (1D zero-based).
        Dim Titles() As String: Titles = Split(TITLES_LIST, TITLE_DELiMITER)
        &#39; Match the title indexes into an array (1D one-based).
        Dim tColIndexes(): tColIndexes = Application.Match(Titles, hrg, 0)
        
        &#39; Write the values from the title columns to a jagged array
        &#39; (1D one-based, containing 2D one-based single-column arrays).
        
        Dim tCount As Long: tCount = UBound(tColIndexes)
        Dim tJag(): ReDim tJag(1 To tCount)
        
        Dim t As Long
        
        For t = 1 To tCount
            tJag(t) = rg.Columns(tColIndexes(t)).Value
        Next t
        
        &#39; Write the unique values from the unique array to the &#39;keys&#39;
        &#39; of a dictionary, and their rows to a collection held
        &#39; by each associated &#39;item&#39;.
        
        Dim dict As Object: Set dict = CreateObject(&quot;Scripting.Dictionary&quot;)
        dict.CompareMode = vbTextCompare
        
        Dim sKey, r As Long, IsFound As Boolean
        
        For r = 1 To rCount
            sKey = uData(r, 1)
            &#39; Exclude error values and blanks.
            If Not IsError(sKey) Then
                If Len(CStr(sKey)) &gt; 0 Then IsFound = True
            End If
            &#39; Write.
            If IsFound Then
                If Not dict.Exists(sKey) Then Set dict(sKey) = New Collection
                dict(sKey).Add r
                IsFound = False &#39; reset for the next iteration
            Else
                uData(r, 1) = INVALID_STRING
            End If
        Next r
                
        &#39; Loop through the &#39;keys&#39; of the dictionary, through the columns
        &#39; of the jagged array, and through the rows in the collections
        &#39; and write the required results to the unique array.
        
        Dim rLen As Long: rLen = Len(RESULT_DELIMITER)
                
        Dim Item, tVal, fr As Long, c As Long, cCount As Long, Result As String
                
        For Each sKey In dict.Keys
            cCount = dict(sKey).Count
            fr = dict(sKey)(1)
            If cCount = 1 Then
                uData(fr, 1) = UNIQUE_STRING
            Else
                For t = 1 To tCount
                    tVal = tJag(t)(fr, 1)
                    For c = 2 To cCount
                        r = dict(sKey)(c)
                        If tJag(t)(r, 1) &lt;&gt; tVal Then Exit For
                    Next c
                    If c &lt;= cCount Then
                        Result = Result &amp; Titles(t - 1) &amp; RESULT_DELIMITER
                    End If
                    Debug.Print t, tVal, c, Result
                Next t
                If Len(Result) = 0 Then
                    Result = DUPE_STRING
                Else
                    Result = Left(Result, Len(Result) - rLen)
                End If
                For c = 1 To cCount
                    uData(dict(sKey)(c), 1) = Result
                Next c
                Result = vbNullString &#39; reset for the next iteration
            End If
        Next sKey
                
        &#39; Write the values from the unique array to the destination column.
        Dim drg As Range: Set drg = rg.Columns(RESULT_COL)
        drg.Value = uData
    
        &#39; Inform.
        MsgBox &quot;Unique values flagged.&quot;, vbInformation
    
    End Sub


  [1]: https://i.stack.imgur.com/Nz1h4.jpg

</details>



huangapple
  • 本文由 发表于 2023年3月9日 23:51:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/75686998.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定