Excel VBA字典:如果数据不符合';与词典不符
几乎在今天,我一直在寻找一种将匹配条件添加到另一个工作簿的方法,但我还没有找到任何方法。示例场景是 下面,我有两个工作簿(workbookA和workbookB),每个工作簿都有自己的“国家”和“价值”列表。请参阅下面的示例表 Workbook("WorkA").Sheet1 Workbook("workB").Sheet1 Country Value Country Value A 10 B B 15 D C 20 E D 25 A E 30 F 35 我想做的是从“workA”中添加一些缺少的国家(在本例中是国家“C”和“F”),然后再次重复匹配过程以收集所有数据。复制粘贴解决方案不适合我的情况,因为我必须收集时间序列数据(贸易数据),而且可能有几个月我感兴趣的国家将与新的合作伙伴进行贸易。我曾尝试在多个网站上对此进行研究,并通过以下链接深入并调整了我的代码与其他人的代码: , 有没有哪位潜在的大师能为我提出解决这类问题的方案或想法?如果你能解释一下代码背后的原因或者我犯的任何错误,那就太好了Excel VBA字典:如果数据不符合';与词典不符,vba,excel,dictionary,Vba,Excel,Dictionary,几乎在今天,我一直在寻找一种将匹配条件添加到另一个工作簿的方法,但我还没有找到任何方法。示例场景是 下面,我有两个工作簿(workbookA和workbookB),每个工作簿都有自己的“国家”和“价值”列表。请参阅下面的示例表 Workbook("WorkA").Sheet1 Workbook("workB").Sheet1 Country Value Country Value
谢谢大家! 我认为你不需要为此使用字典-你可以检查
Book1
,columna
中的每个值,检查它是否存在于Book2
columna
中的范围内,如果存在,你可以移植到它对应的值上-如果没有,则将它添加到末尾并将其关联的值带过来。这是一个简单、动态的解决方案
注意的简单用法。查找返回行位置:
Sub Test_match_fill_data()
Dim aCell
Dim i, j As Long, keyrow As Long
Dim w1, w2 As Worksheet
Set w1 = Workbooks("Book1").Sheets("Sheet1")
Set w2 = Workbooks("Book2").Sheets("Sheet1")
i = w1.Cells(w1.Rows.Count, 1).End(xlUp).Row
j = w2.Cells(w2.Rows.Count, 1).End(xlUp).Row
For Each aCell In w1.Range("A2:A" & i)
On Error Resume Next
keyrow = w2.Columns("A:A").Find(What:=aCell, LookAt:=xlWhole).Row
On Error GoTo 0
If keyrow = 0 Then
w2.Range("A" & j + 1).Value = aCell
w2.Range("B" & j + 1).Value = aCell.Offset(0, 1).Value
j = j + 1
Else
w2.Range("B" & keyrow).Value = aCell.Offset(0, 1).Value
End If
keyrow = 0
Next
End Sub
只需对代码进行最小的更改:
Sub Test_match_fill_data()
Dim Dict As Object
Dim key As Variant
Dim aCell As Range, bCell As Range
Dim i As Long, j As Long
Dim w1 As Worksheet, w2 As Worksheet
Set Dict = CreateObject("Scripting.Dictionary")
Set w1 = Workbooks("workA").Sheets("Sheet1")
Set w2 = Workbooks("workB").Sheets("Sheet1")
i = w1.Cells(w1.Rows.Count, 1).End(xlUp).row
For Each aCell In w1.Range("A6:A" & i)
Dict(aCell.Value) = aCell.Offset(0, 2).Value
Next
j = w2.Cells(w2.Rows.Count, 1).End(xlUp).row
For Each bCell In w2.Range("A6:A" & j)
If Dict.Exists(bCell.Value) Then
bCell.Offset(0, 2).Value = Dict(bCell.Value)
Dict.Remove bCell.Value
End If
Next
For Each key In Dict
With w2.Cells(w2.Rows.Count, 1).End(xlUp).Offset(1)
.Value = key
.Offset(,2) = Dict(key)
End With
Next
End Sub
而稍微精简一点的版本可能是:
Sub Test_match_fill_data()
Dim Dict As Object
Dim key As Variant
Dim cell As Range
Set Dict = CreateObject("Scripting.Dictionary")
With Workbooks("workA").Sheets("Sheet1")
For Each cell In .Range("A6", .Cells(.Rows.count, 1).End(xlUp))
Dict(cell.Value) = cell.Offset(0, 2).Value
Next
End With
With Workbooks("workB").Sheets("Sheet1")
For Each cell In .Range("A6", .Cells(Rows.count, 1).End(xlUp))
If Dict.Exists(cell.Value) Then
cell.Offset(0, 2).Value = Dict(cell.Value)
Dict.Remove cell.Value
End If
Next
For Each key In Dict
With .Cells(.Rows.count, 1).End(xlUp).Offset(1)
.Value = key
.Offset(, 2) = Dict(key)
End With
Next
End With
End Sub
对于“快速快速”代码,您需要大量使用数组和字典,并将excel工作表范围的访问限制到最低限度
因此,下面的代码是从我的上一个代码中获得的,但将excel工作表的访问范围限制为初始数据读取和最终数据写入,这两种方式都是“一次性”模式(或接近)
如果您只是复制粘贴它,顺序会有所不同-当这发现w2
中不存在的第一条记录时,它被添加到底部,其值被带过来。@DisplayName Oops,我粘贴了错误的图像!谢谢你注意到hi@dwirony,谢谢你的建议。由于我是一个缺乏VBA编码经验的初学者,我无法生成那种动态解决方案。老实说,我更喜欢你的代码而不是我的代码,因为它简单,易于重新访问,并且对即将到来的新数据进行了良好的组织。很抱歉没有给你一个正确的标记作为我关于VBA字典的标题。感谢您分享您的知识,并教我一个简单的动态解决方案。如果有机会,我一定会将您的代码应用到我的工作中:)Hi@DisplayName,首先感谢您的帮助和及时回复。在我尝试使用你的代码后,我发现了一个很小的错误。在不进行任何编辑的情况下,您的代码将在普通国家/地区返回空白,但会添加缺少的国家/地区及其值。这是我的错误,我没有解释清楚。我真正想要的是来自共同国家和缺失国家的数据。不过,我已经把你的代码和我的代码结合起来了,到目前为止,它运行得很好。再次感谢你的建议,我非常感激:)不客气。然后你可以考虑把答案标记为“接受”。非常感谢。至于你所说的“微小错误”,请考虑我从代码中采用了<代码>偏移(2)<代码>,所以它从“C”栏中读取“值”,即“国家”栏右边的两列(列A)。基于这个假设,我根据您的数据测试了我的代码,它成功了。我可以征求您的意见吗?我是应该使用这个字典脚本,还是使用@dwirony?发布的动态解决方案,如下所示?。我的条件是我想尽快处理这些文件,因为它们有大量的文件等待处理。我不知道哪种解决方案需要我更多的时间。对这件事有什么意见吗?好吧,两个都试试!但大家都知道,dicts和array方法比工作表单元格读写速度快得多,这是我对这方面的最新认识。如果是这样,让我两个都试试。再次感谢您的帮助和意见。干杯D
Sub Test_match_fill_data()
Dim Dict As Object
Dim key As Variant
Dim cell As Range
Set Dict = CreateObject("Scripting.Dictionary")
With Workbooks("workA").Sheets("Sheet1")
For Each cell In .Range("A6", .Cells(.Rows.count, 1).End(xlUp))
Dict(cell.Value) = cell.Offset(0, 2).Value
Next
End With
With Workbooks("workB").Sheets("Sheet1")
For Each cell In .Range("A6", .Cells(Rows.count, 1).End(xlUp))
If Dict.Exists(cell.Value) Then
cell.Offset(0, 2).Value = Dict(cell.Value)
Dict.Remove cell.Value
End If
Next
For Each key In Dict
With .Cells(.Rows.count, 1).End(xlUp).Offset(1)
.Value = key
.Offset(, 2) = Dict(key)
End With
Next
End With
End Sub
Sub Test_match_fill_data()
Dim Dict As Object
Dim iItem As Long
Dim workACountries As Variant, workAValues As Variant
Dim workBCountries As Variant, workBValues As Variant
With Workbooks("workA").Sheets("Sheet1")
workACountries = .Range("A6", .Cells(.Rows.count, 1).End(xlUp)).Value
workAValues = .Range("C6:C" & .Cells(.Rows.count, 1).End(xlUp).Row).Value
End With
Set Dict = CreateObject("Scripting.Dictionary")
For iItem = 1 To UBound(workACountries)
Dict(workACountries(iItem, 1)) = workAValues(iItem, 1)
Next
With Workbooks("workB").Sheets("Sheet1")
workBCountries = .Range("A6", .Cells(.Rows.count, 1).End(xlUp)).Value
workBValues = .Range("C6:C" & .Cells(.Rows.count, 1).End(xlUp).Row).Value
End With
For iItem = 1 To UBound(workBCountries)
If Dict.Exists(workBCountries(iItem, 1)) Then
workBValues(iItem, 1) = Dict(workBCountries(iItem, 1))
Dict.Remove workBCountries(iItem, 1)
End If
Next
With Workbooks("workB").Sheets("Sheet1")
.Range("A6").Resize(UBound(workBCountries)).Value = workBCountries
.Range("C6").Resize(UBound(workBCountries)).Value = workBValues
.Cells(.Rows.count, 1).End(xlUp).Offset(1).Resize(Dict.count).Value = Application.Transpose(Dict.Keys)
.Cells(.Rows.count, 3).End(xlUp).Offset(1).Resize(Dict.count).Value = Application.Transpose(Dict.Items)
End With
End Sub