简体   繁体   English

Excel VBA - 获取跨列的唯一条目列表并将其合并为一列唯一项

[英]Excel VBA - Getting a list of unique entries across various columns and combine into a single column of unique items

I am trying to get a list of unique data from multiple columns into a single column.我正在尝试将多列中的唯一数据列表放入单列中。

I found the following code which works great;我发现以下代码效果很好;

RanglFilterCopy, CopyToRange:=Range("B1"), Uniqe("A1:A6").AdvancedFilter Action:=xue:=True

Source of this was (and thank you to https://stackoverflow.com/users/495455/jeremy-thompson for posting): Quicker way to get all unique values of a column in VBA?其来源是(感谢https://stackoverflow.com/users/495455/jeremy-thompson发布): 在 VBA 中获取列的所有唯一值的更快方法?

My issue is, I don't want to be limited to a set range (ie I want the range to be dynamic based on the entered data) as the range may change and I want to capture unique values across multiple columns, not just 1.我的问题是,我不想被限制在一个设定的范围内(即我希望范围根据输入的数据是动态的),因为范围可能会改变,我想在多个列中捕获唯一值,而不仅仅是 1 .

I am thinking that I need to do something along the following lines but really am lost where to start in terms of VBA code.我想我需要按照以下几行做一些事情,但在 VBA 代码方面真的迷失了从哪里开始。

  1. Get all values from Column (1) and copy to a new Column (x)从列 (1) 中获取所有值并复制到新列 (x)
  2. Get all values from Column (2...n) and add the data to the next empty cell in Column (x) NOTE: Column selection is not sequential (ie May be Column 1, 4, 7 and 9 rather than 1,2,3,4,5,6,7,8,9 if that makes a difference in terms of being able to loop through a range)从列 (2...n) 中获取所有值并将数据添加到列 (x) 中的下一个空单元格注意:列选择不是连续的(即可能是第 1、4、7 和 9 列而不是 1,2 ,3,4,5,6,7,8,9 如果这在能够循环范围方面有所不同)
  3. Once all Columns (1...n) are copied across to Column (x), check Column (x), work out the unique values and transfer only these unique values to Column (y)将所有列 (1...n) 复制到列 (x) 后,检查列 (x),计算出唯一值并仅将这些唯一值传输到列 (y)
  4. Check Column (y) a final time to ensure there are no duplicated (if there are correct them)最后一次检查列 (y) 以确保没有重复(如果有正确的话)
  5. Clean up and get rid of everything except the original source data within the Table and Column (y) which hopefully now contains my unique values (ie get rid of Column (x)).清理并删除除表和列 (y) 中的原始源数据之外的所有内容,它们希望现在包含我的唯一值(即删除列 (x))。

Points to consider;要考虑的要点;

  1. The data is contained in "Columns" within a "Table" on a specific worksheet Example of a Column within my Table is -> Range("Table1[StileCode]")数据包含在特定工作表上“表格”内的“列”中我的表格中的列示例是 -> Range("Table1[StileCode]")
  2. I want to specify the start cell in Column (y) to place the unique values which will be on a different worksheet to the source data.我想在列 (y) 中指定起始单元格以将唯一值放置在与源数据不同的工作表上。
  3. The data added to the target sheet and column, ie Column (y) will ideally be contained in a "Named Range" on the worksheet.添加到目标工作表和列(即列 (y))的数据最好包含在工作表的“命名范围”中。
  4. The "Named Range" is used in formulas on the source worksheet via an index/match scenario (ie the reason I want unique values). “命名范围”通过索引/匹配方案在源工作表上的公式中使用(即我想要唯一值的原因)。

Summary I want to basically dynamically create a unique list on the fly (or when I choose to run the code) which captures all the unique values at that point in time.总结 我想基本上动态地动态创建一个唯一的列表(或者当我选择运行代码时),该列表捕获该时间点的所有唯一值。

I know this is a big ask but any assistance/guidance would be greatly appreciated.我知道这是一个很大的问题,但任何帮助/指导将不胜感激。

OK - Done a little homework and the following seems to work, please don't laugh, I am no VBA expert so I am imagining that the code is clunky and could most probably be achieved with less code.好的 - 做了一点功课,以下似乎有效,请不要笑,我不是 VBA 专家,所以我想象代码很笨重,很可能用更少的代码来实现。

Any suggestions would be appreciated.任何建议将不胜感激。

I created a new workbook with Sheet1 and Sheet 2.我用 Sheet1 和 Sheet 2 创建了一个新工作簿。

The data is in columns A, B, C, D and E of Sheet1.数据位于 Sheet1 的 A、B、C、D 和 E 列中。

数据表

Code as follows;代码如下;

Sub TestTheoryCopy()
    Dim sourceWS As Worksheet
    Dim targetWS As Worksheet
    Dim sourceValues As Range
    Dim targetRange As Range

    Set sourceWS = ThisWorkbook.Sheets("Sheet1")
    Set targetWS = ThisWorkbook.Sheets("Sheet2")

    Dim i As Integer

    Dim dataColA As Integer
    dataColA = 1

    Dim dataColC As Integer
    dataColC = 3

    Dim dataColE As Integer
    dataColE = 5

    Dim startRange As Range
    Dim ra As Range

    targetWS.Cells.Clear

    For i = dataColA To dataColA
        Set startRange = sourceWS.Range("A2").Offset(0, i - 1)
        Set ra = sourceWS.Range(startRange, sourceWS.Cells(Rows.Count, startRange.Column).End(xlUp))
        ra.Copy
        targetWS.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
    Next i

    For i = dataColC To dataColC
        Set startRange = sourceWS.Range("A2").Offset(0, i - 1)
        Set ra = sourceWS.Range(startRange, sourceWS.Cells(Rows.Count, startRange.Column).End(xlUp))
        ra.Copy
        targetWS.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
    Next i

    For i = dataColE To dataColE
        Set startRange = sourceWS.Range("A2").Offset(0, i - 1)
        Set ra = sourceWS.Range(startRange, sourceWS.Cells(Rows.Count, startRange.Column).End(xlUp))
        ra.Copy
        targetWS.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
    Next i

    targetWS.Activate

    RemoveBlankCells 'If blank cells are included I wanted to remove them from the dataset

    Dim FoundFromColumnsRangeA As Range
    Dim uniqueIDs As Range

    Set FoundFromColumnsRangeA = Sheets("Sheet2").UsedRange
    FoundFromColumnsRangeA.Columns(1).Select

    With Selection
        .AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("B1"), Unique:=True
    End With

    Set uniqueIDs = Sheets("Sheet2").UsedRange
    FoundFromColumnsRangeA.Columns(2).Select

    With Selection
        .AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("C2"), Unique:=True
    End With

    RemoveBlankCells

    Columns("A:B").EntireColumn.Delete

End Sub

Private Sub RemoveBlankCells()
'PURPOSE: Deletes single cells that are blank located inside a designated range
'SOURCE: www.TheSpreadsheetGuru.com

Dim ws As Worksheet
Dim rng As Range

Set ws = ThisWorkbook.Sheets("Sheet2")

'Store blank cells inside a variable
  On Error GoTo NoBlanksFound
    Set rng = ws.Range("A:A").SpecialCells(xlCellTypeBlanks)
  On Error GoTo 0

'Delete blank cells and shift upward
  rng.Rows.Delete Shift:=xlShiftUp

Exit Sub

'ERROR HANLDER
NoBlanksFound:
  MsgBox "No Blank cells were found"

End Sub

} }

In this day and age I would use Power Query / Get and Transform.在这个时代,我会使用 Power Query/Get 和 Transform。 Pull all the data tables into queries, delete all but the one column you are interested in, append the queries and delete duplicates.将所有数据表拉入查询,删除除您感兴趣的一列之外的所有数据表,附加查询并删除重复项。

If the data changes, just hit the Refresh All button.如果数据发生变化,只需点击“全部刷新”按钮。 Viola.中提琴。

Here is some code that should run reasonably quickly.下面是一些应该可以相当快地运行的代码。 As written, the Table name, worksheet names, and the particular columns to copy are hard coded.正如所写,表名称、工作表名称和要复制的特定列是硬编码的。

The data is read into a variant array for speed of processing (usually faster than accessing the worksheets).数据被读入变体数组以提高处理速度(通常比访问工作表更快)。

The Collection object is used to remove duplicates (and blanks are tested for and skipped). Collection对象用于删除重复项(测试并跳过空白)。 One could use the Dictionary object, and which would be faster depends on the size of the data.可以使用Dictionary对象,哪个更快取决于数据的大小。 Other differences:其他区别:

  • The Collection object throws an error if you have a duplicate key.如果您有重复的键,则Collection对象会引发错误。
  • The Dictionary object has a .Exists method Dictionary对象有一个.Exists方法
  • The Dictionary object requires early or late binding to Microsoft Scripting Runtime Dictionary对象需要早期或晚期绑定到Microsoft Scripting Runtime
  • The Collection object is native VBA. Collection对象是本机 VBA。

Hopefully, this code will give you some clues.希望这段代码能给你一些线索。

Option Explicit
Sub deDupe()
    Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range
    Dim vSrc As Variant, vRes As Variant
    Dim cUniques As Collection
    Dim I As Long, J As Long
    Dim colArray
    Dim V

'Columns to include
' 1 = first column in table
colArray = Array(1, 3, 5) 'Note this will be zero-based array

'Change sheet names for data and results as needed
Set wsSrc = Worksheets("sheet1")
Set wsRes = Worksheets("sheet2")
    Set rRes = wsRes.Cells(1, 1) 'put first cell of unique list anyplace

'Read data into variant array for speed
vSrc = wsSrc.ListObjects("Table1").DataBodyRange

'Collect the unique values
Set cUniques = New Collection
On Error Resume Next 'Duplicate keys in .Add method --> error
For J = 0 To UBound(colArray)
    For I = 1 To UBound(vSrc)
        V = vSrc(I, colArray(J))
        If V <> "" Then
            cUniques.Add Item:=V, Key:=CStr(V)
        End If
    Next I
Next J
On Error GoTo 0

'create results array
ReDim vRes(1 To cUniques.Count, 1 To 1)
For I = 1 To UBound(vRes, 1)
    vRes(I, 1) = cUniques(I)
Next I

'Write the results
Set rRes = rRes.Resize(UBound(vRes, 1), 1)
With rRes
    .EntireColumn.Clear
    .Value = vRes
    .EntireColumn.AutoFit
End With

End Sub

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM