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

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

VBA - Find and compare values in multiple columns

问题

  1. Sub CheckSame()
  2. Dim i As Integer
  3. Dim lastRow As Long
  4. lastRow = Cells(Rows.Count, 1).End(xlUp).Row
  5. For i = 3 To lastRow
  6. If Cells(i, 13) = Cells(i - 1, 13) Then
  7. 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
  8. Cells(i, 36) = "Same"
  9. 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
  10. Cells(i, 36) = "Name"
  11. 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
  12. Cells(i, 36) = "Date"
  13. 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
  14. Cells(i, 36) = "Active"
  15. 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
  16. Cells(i, 36) = "Dept"
  17. End If
  18. End If
  19. Next i
  20. 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

'''

  1. Sub CheckSame()
  2. Dim i As Integer
  3. Dim lastRow As Long
  4. lastRow = Cells(Rows.Count, 1).End(xlUp).Row
  5. For i = 3 To lastRow
  6. If Cells(i, 13) = Cells(i - 1, 13) Then
  7. 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
  8. Cells(i, 36) = "Same"
  9. 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
  10. Cells(i, 36) = "Name"
  11. 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
  12. Cells(i, 36) = "Date"
  13. 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
  14. Cells(i, 36) = "Active"
  15. 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
  16. Cells(i, 36) = "Dept"
  17. End If
  18. End If
  19. Next i
  20. End Sub

'''

答案1

得分: 2

以下是你要翻译的内容:

  1. Option Explicit
  2. Const SHOWPC = True
  3. Sub CompareCols()
  4. Const COL_ID = "M"
  5. Const COL_NAME = "AE"
  6. Const COL_RESULT = "AJ"
  7. Dim ws As Worksheet, lastrow As Long, i As Long, j As Long
  8. Dim arDict, arCol, v, n As Long, msg As String
  9. arCol = Array("Name", "Date", "Active", "Dept")
  10. ReDim arDict(UBound(arCol)) As Object
  11. For i = 0 To UBound(arDict)
  12. Set arDict(i) = CreateObject("Scripting.Dictionary")
  13. Next
  14. Set ws = ThisWorkbook.Sheets("Sheet1")
  15. With ws
  16. lastrow = .Cells(.Rows.Count, COL_ID).End(xlUp).Row
  17. For i = 2 To lastrow
  18. For j = 0 To 3
  19. v = .Cells(i, "AE").Offset(, j)
  20. arDict(j)(v) = arDict(j)(v) + 1 ' count of this value
  21. Next
  22. n = n + 1
  23. ' is this last in group
  24. If .Cells(i + 1, COL_ID) <> .Cells(i, COL_ID) Then
  25. .Cells(i - n + 1, COL_RESULT).Resize(n, 5) = CompareRows(arDict, arCol)
  26. n = 0
  27. End If
  28. Next
  29. End With
  30. MsgBox lastrow - 1 & " rows scanned", vbInformation
  31. End Sub
  32. Function CompareRows(ByRef arDict, arCol) As Variant
  33. Dim v, s As String, sep As String, pc As String
  34. Dim n As Long, i As Long, tot As Long, m As Long
  35. n = UBound(arCol) ' cols to check
  36. Dim arCount: ReDim arCount(n) As Long
  37. Dim arResult: ReDim arResult(1 To 1, 1 To n + 2)
  38. ' check each column
  39. For i = 0 To n
  40. tot = 0
  41. For Each v In arDict(i).Keys
  42. m = arDict(i)(v) 'count of value
  43. tot = tot + m
  44. ' take v with most entries
  45. If m > arCount(i) Then
  46. arCount(i) = m
  47. arResult(1, i + 2) = v
  48. End If
  49. Next
  50. ' add pcent
  51. If SHOWPC Then
  52. pc = Format(arCount(i) / tot, " (0%)")
  53. arResult(1, i + 2) = arResult(1, i + 2) & pc
  54. End If
  55. If arDict(i).Count > 1 Then
  56. s = s & sep & arCol(i)
  57. sep = ","
  58. End If
  59. arDict(i).RemoveAll ' clear dictionary
  60. Next
  61. If s = "" Then s = "Same"
  62. arResult(1, 1) = s
  63. CompareRows = arResult
  64. 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.

  1. Option Explicit
  2. Const SHOWPC = True
  3. Sub CompareCols()
  4. Const COL_ID = &quot;M&quot;
  5. Const COL_NAME = &quot;AE&quot;
  6. Const COL_RESULT = &quot;AJ&quot;
  7. Dim ws As Worksheet, lastrow As Long, i As Long, j As Long
  8. Dim arDict, arCol, v, n As Long, msg As String
  9. arCol = Array(&quot;Name&quot;, &quot;Date&quot;, &quot;Active&quot;, &quot;Dept&quot;)
  10. ReDim arDict(UBound(arCol)) As Object
  11. For i = 0 To UBound(arDict)
  12. Set arDict(i) = CreateObject(&quot;Scripting.DIctionary&quot;)
  13. Next
  14. Set ws = ThisWorkbook.Sheets(&quot;Sheet1&quot;)
  15. With ws
  16. lastrow = .Cells(.Rows.Count, COL_ID).End(xlUp).Row
  17. For i = 2 To lastrow
  18. For j = 0 To 3
  19. v = .Cells(i, &quot;AE&quot;).Offset(, j)
  20. arDict(j)(v) = arDict(j)(v) + 1 &#39; count of this value
  21. Next
  22. n = n + 1
  23. &#39; is this last in group
  24. If .Cells(i + 1, COL_ID) &lt;&gt; .Cells(i, COL_ID) Then
  25. .Cells(i - n + 1, COL_RESULT).Resize(n, 5) = CompareRows(arDict, arCol)
  26. n = 0
  27. End If
  28. Next
  29. End With
  30. MsgBox lastrow - 1 &amp; &quot; rows scanned&quot;, vbInformation
  31. End Sub
  32. Function CompareRows(ByRef arDict, arCol) As Variant
  33. Dim v, s As String, sep As String, pc As String
  34. Dim n As Long, i As Long, tot As Long, m As Long
  35. n = UBound(arCol) &#39; cols to check
  36. Dim arCount: ReDim arCount(n) As Long
  37. Dim arResult: ReDim arResult(1 To 1, 1 To n + 2)
  38. &#39; check each column
  39. For i = 0 To n
  40. tot = 0
  41. For Each v In arDict(i).keys
  42. m = arDict(i)(v) &#39;count of value
  43. tot = tot + m
  44. &#39; take v with most entries
  45. If m &gt; arCount(i) Then
  46. arCount(i) = m
  47. arResult(1, i + 2) = v
  48. End If
  49. Next
  50. &#39; add pcent
  51. If SHOWPC Then
  52. pc = Format(arCount(i) / tot, &quot; (0%)&quot;)
  53. arResult(1, i + 2) = arResult(1, i + 2) &amp; pc
  54. End If
  55. If arDict(i).Count &gt; 1 Then
  56. s = s &amp; sep &amp; arCol(i)
  57. sep = &quot;,&quot;
  58. End If
  59. arDict(i).RemoveAll &#39; clear dictionary
  60. Next
  61. If s = &quot;&quot; Then s = &quot;Same&quot;
  62. arResult(1, 1) = s
  63. CompareRows = arResult
  64. End Function
  65. </details>
  66. # 答案2
  67. **得分**: 0
  68. 以下是代码部分的翻译:
  69. ```vb
  70. Option Explicit
  71. Sub FlagUniques()
  72. ' 定义常量。
  73. Const WS_NAME As String = "Sheet1"
  74. Const UNIQUE_COL As String = "M"
  75. Const RESULT_COL As String = "AJ"
  76. Const TITLES_LIST As String = "Name,Date,Active,Dept"
  77. Const TITLE_DELiMITER As String = ","
  78. Const DUPE_STRING As String = "Same"
  79. Const UNIQUE_STRING As String = "Unique"
  80. Const INVALID_STRING As String = "Invalid"
  81. Const RESULT_DELIMITER As String = ", "
  82. ' 引用工作簿。
  83. Dim wb As Workbook: Set wb = ThisWorkbook ' 包含此代码的工作簿
  84. ' 引用工作表。
  85. Dim ws As Worksheet: Set ws = wb.Sheets(WS_NAME)
  86. Dim rg As Range: Set rg = ws.Range("A1").CurrentRegion ' 包含标题
  87. Dim hrg As Range: Set hrg = rg.Rows(1) ' 标题
  88. Dim rCount As Long: rCount = rg.Rows.Count - 1 ' 没有标题
  89. Set rg = rg.Resize(rCount).Offset(1) ' 没有标题
  90. ' 将唯一列的值写入数组(2D 基于一的数组)。
  91. Dim uData(): uData = rg.Columns(UNIQUE_COL).Value
  92. ' 将标题从列表中拆分为数组(1D 基于零的数组)。
  93. Dim Titles() As String: Titles = Split(TITLES_LIST, TITLE_DELiMITER)
  94. ' 将标题的索引匹配到数组中(1D 基于一的数组)。
  95. Dim tColIndexes(): tColIndexes = Application.Match(Titles, hrg, 0)
  96. ' 将标题列的值写入一个交错数组
  97. ' (1D 基于一的数组,包含基于一的2D 单列数组)。
  98. Dim tCount As Long: tCount = UBound(tColIndexes)
  99. Dim tJag(): ReDim tJag(1 To tCount)
  100. Dim t As Long
  101. For t = 1 To tCount
  102. tJag(t) = rg.Columns(tColIndexes(t)).Value
  103. Next t
  104. ' 将唯一数组中的唯一值写入字典的“键”,
  105. ' 并将它们的行写入由每个相关“项”持有的集合中。
  106. Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
  107. dict.CompareMode = vbTextCompare
  108. Dim sKey, r As Long, IsFound As Boolean
  109. For r = 1 To rCount
  110. sKey = uData(r, 1)
  111. ' 排除错误值和空白。
  112. If Not IsError(sKey) Then
  113. If Len(CStr(sKey)) > 0 Then IsFound = True
  114. End If
  115. ' 写入。
  116. If IsFound Then
  117. If Not dict.Exists(sKey) Then Set dict(sKey) = New Collection
  118. dict(sKey).Add r
  119. IsFound = False ' 为下一次迭代重置
  120. Else
  121. uData(r, 1) = INVALID_STRING
  122. End If
  123. Next r
  124. ' 循环遍历字典的“键”,遍历交错数组的列,
  125. ' 并遍历集合中的行,并将所需的结果写入唯一数组。
  126. Dim rLen As Long: rLen = Len(RESULT_DELIMITER)
  127. Dim Item, tVal, fr As Long, c As Long, cCount As Long, Result As String
  128. For Each sKey In dict.Keys
  129. cCount = dict(sKey).Count
  130. fr = dict(sKey)(1)
  131. If cCount = 1 Then
  132. uData(fr, 1) = UNIQUE_STRING
  133. Else
  134. For t = 1 To tCount
  135. tVal = tJag(t)(fr, 1)
  136. For c = 2 To cCount
  137. r = dict(sKey)(c)
  138. If tJag(t)(r, 1) <> tVal Then Exit For
  139. Next c
  140. If c <= cCount Then
  141. Result = Result & Titles(t - 1) & RESULT_DELIMITER
  142. End If
  143. Debug.Print t, tVal, c, Result
  144. Next t
  145. If Len(Result) = 0 Then
  146. Result = DUPE_STRING
  147. Else
  148. Result = Left(Result, Len(Result) - rLen)
  149. End If
  150. For c = 1 To cCount
  151. uData(dict(sKey)(c), 1) = Result
  152. Next c
  153. Result = vbNullString ' 为下一次迭代重置
  154. End If
  155. Next sKey
  156. ' 将唯一数组中的值写入目标列。
  157. Dim drg As Range: Set drg = rg.Columns(RESULT_COL)
  158. drg.Value = uData
  159. ' 通知。
  160. MsgBox "唯一值已标记。", vbInformation
  161. End Sub
  162. ```
  163. <details>
  164. <summary>英文:</summary>
  165. Flag Unique Values
  166. -
  167. [![enter image description here][1]][1]
  168. &lt;!-- language: lang-vb --&gt;
  169. Option Explicit
  170. Sub FlagUniques()
  171. &#39; Define constants.
  172. Const WS_NAME As String = &quot;Sheet1&quot;
  173. Const UNIQUE_COL As String = &quot;M&quot;
  174. Const RESULT_COL As String = &quot;AJ&quot;
  175. Const TITLES_LIST As String = &quot;Name,Date,Active,Dept&quot;
  176. Const TITLE_DELiMITER As String = &quot;,&quot;
  177. Const DUPE_STRING As String = &quot;Same&quot;
  178. Const UNIQUE_STRING As String = &quot;Unique&quot;
  179. Const INVALID_STRING As String = &quot;Invalid&quot;
  180. Const RESULT_DELIMITER As String = &quot;, &quot;
  181. &#39; Reference the workbook.
  182. Dim wb As Workbook: Set wb = ThisWorkbook &#39; workbook containing this code
  183. &#39; Reference the range.
  184. Dim ws As Worksheet: Set ws = wb.Sheets(WS_NAME)
  185. Dim rg As Range: Set rg = ws.Range(&quot;A1&quot;).CurrentRegion &#39; has headers
  186. Dim hrg As Range: Set hrg = rg.Rows(1) &#39; header
  187. Dim rCount As Long: rCount = rg.Rows.Count - 1 &#39; no headers
  188. Set rg = rg.Resize(rCount).Offset(1) &#39; no headers
  189. &#39; Write the values from the unique column to an array (2D one-based).
  190. Dim uData(): uData = rg.Columns(UNIQUE_COL).Value
  191. &#39; Split the titles from the list into an array (1D zero-based).
  192. Dim Titles() As String: Titles = Split(TITLES_LIST, TITLE_DELiMITER)
  193. &#39; Match the title indexes into an array (1D one-based).
  194. Dim tColIndexes(): tColIndexes = Application.Match(Titles, hrg, 0)
  195. &#39; Write the values from the title columns to a jagged array
  196. &#39; (1D one-based, containing 2D one-based single-column arrays).
  197. Dim tCount As Long: tCount = UBound(tColIndexes)
  198. Dim tJag(): ReDim tJag(1 To tCount)
  199. Dim t As Long
  200. For t = 1 To tCount
  201. tJag(t) = rg.Columns(tColIndexes(t)).Value
  202. Next t
  203. &#39; Write the unique values from the unique array to the &#39;keys&#39;
  204. &#39; of a dictionary, and their rows to a collection held
  205. &#39; by each associated &#39;item&#39;.
  206. Dim dict As Object: Set dict = CreateObject(&quot;Scripting.Dictionary&quot;)
  207. dict.CompareMode = vbTextCompare
  208. Dim sKey, r As Long, IsFound As Boolean
  209. For r = 1 To rCount
  210. sKey = uData(r, 1)
  211. &#39; Exclude error values and blanks.
  212. If Not IsError(sKey) Then
  213. If Len(CStr(sKey)) &gt; 0 Then IsFound = True
  214. End If
  215. &#39; Write.
  216. If IsFound Then
  217. If Not dict.Exists(sKey) Then Set dict(sKey) = New Collection
  218. dict(sKey).Add r
  219. IsFound = False &#39; reset for the next iteration
  220. Else
  221. uData(r, 1) = INVALID_STRING
  222. End If
  223. Next r
  224. &#39; Loop through the &#39;keys&#39; of the dictionary, through the columns
  225. &#39; of the jagged array, and through the rows in the collections
  226. &#39; and write the required results to the unique array.
  227. Dim rLen As Long: rLen = Len(RESULT_DELIMITER)
  228. Dim Item, tVal, fr As Long, c As Long, cCount As Long, Result As String
  229. For Each sKey In dict.Keys
  230. cCount = dict(sKey).Count
  231. fr = dict(sKey)(1)
  232. If cCount = 1 Then
  233. uData(fr, 1) = UNIQUE_STRING
  234. Else
  235. For t = 1 To tCount
  236. tVal = tJag(t)(fr, 1)
  237. For c = 2 To cCount
  238. r = dict(sKey)(c)
  239. If tJag(t)(r, 1) &lt;&gt; tVal Then Exit For
  240. Next c
  241. If c &lt;= cCount Then
  242. Result = Result &amp; Titles(t - 1) &amp; RESULT_DELIMITER
  243. End If
  244. Debug.Print t, tVal, c, Result
  245. Next t
  246. If Len(Result) = 0 Then
  247. Result = DUPE_STRING
  248. Else
  249. Result = Left(Result, Len(Result) - rLen)
  250. End If
  251. For c = 1 To cCount
  252. uData(dict(sKey)(c), 1) = Result
  253. Next c
  254. Result = vbNullString &#39; reset for the next iteration
  255. End If
  256. Next sKey
  257. &#39; Write the values from the unique array to the destination column.
  258. Dim drg As Range: Set drg = rg.Columns(RESULT_COL)
  259. drg.Value = uData
  260. &#39; Inform.
  261. MsgBox &quot;Unique values flagged.&quot;, vbInformation
  262. End Sub
  263. [1]: https://i.stack.imgur.com/Nz1h4.jpg
  264. </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:

确定