当我从Excel(在单元格中)调用该函数时:
=allVlookup(O24,A:D,3,"")
vs via vba
MsgBox allVlookup(Range("O24"), Range("A:D"), 3, "")
我得到了不同的结果。当从Excel调用时,我只获得第一个匹配,但是当从具有相同参数的vba测试子调用时(除了将Range
添加到允许子运行的参数之外),我得到完整的结果(这是不止一个)。
我正在使用的功能是:
Public Function allVlookup(lookupRange As Range, tableRange As Range, colIndex As Integer, Optional delimiter As String = "") As String
Dim c As Range
Dim firstAddress As String
'MsgBox tableRange.Address ' this is correct
'With Sheets(4).Range("A1:C12").Columns(1)
'With Range("A1:C12").Columns(1)
'this doesn't allow things to work right either (???)
'Set tableRange = Range("A:D")
'Set lookupRange = Range("O24")
'search only the first column for matches
With tableRange.Columns(1)
Set c = .Find(what:=lookupRange.Value, LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
'add the delimiter
If (allVlookup <> "") Then
allVlookup = allVlookup + delimiter
End If
'append value to previous value
allVlookup = allVlookup + c.Offset(0, colIndex).Value
Set c = .FindNext(c)
'exit conditions
'no match found
If (c Is Nothing) Then
Exit Do
'we're back to start
ElseIf (c.Address = firstAddress) Then
Exit Do
End If
Loop
End If
End With
End Function
我无法解释为什么会这样。
如何才能使输出完全相同?
答案 0 :(得分:2)
请不要逻辑,但这里是给出相同结果的解决方案。将.Find
行更改为:
Set c = .Find(what:=lookupRange.Value2, after:=.Cells(1), LookIn:=xlValues, LookAt:=xlWhole)
并另外将.FindNext
更改为:
Set c = .Find(what:=lookupRange.Value2, after:=c, LookIn:=xlValues, LookAt:=xlWhole)
请注意,tableRange
范围应该包含列标题。如果没有,结果顺序将不会像第一眼看到的那样。
最后一句的附加(EDITED)解释。如果你有这种类型的表:
| A | B | C | D |
--+-----+-----+-----+-----+
1 | ABC 1 2 A
2 | ABC 3 4 B
3 | ABC 5 6 C
在range("A1:D3")
中搜索ABC以从D列获取数据时,您将获得结果:BCD
。要获得ABC
,第一行应该有列标题。
答案 1 :(得分:2)
它只给出第一场比赛的原因是因为一个错误。请在底部查看此link(第5部分)。
我很久以前就把它作为一个bug提交了。如果您阅读上述链接,那么我也建议了替代代码。
如果链接死亡(不应该),则从该链接中提取
.FindNext无法按预期在用户定义的函数中工作。您可以在正常功能中使用它。
让我们说我们在Sheet1中有这些数据:
A1 → Colt
A2 → Holt
A3 → Dolt
A4 → Hello
并在
B1 → olt
现在,如果我们将以下代码粘贴到模块中并运行它,那么我们将获得预期结果$A$1:$A$3
Sub Test()
Sample Sheets("Sheet1").Range("B1"), Sheets("Sheet1").Range("A1:A4")
End Sub
Sub Sample(FirstRange As Range, ListRange As Range)
Dim aCell As Range, bCell As Range, oRange As Range
Dim ExitLoop As Boolean
Set oRange = ListRange.Find(what:=FirstRange.Value, LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not oRange Is Nothing Then
Set bCell = oRange: Set aCell = oRange
Do While ExitLoop = False
Set oRange = ListRange.FindNext(After:=oRange)
If Not oRange Is Nothing Then
If oRange.Address = bCell.Address Then Exit Do
Set aCell = Union(aCell, oRange)
Else
ExitLoop = True
End If
Loop
MsgBox aCell.Address
Else
MsgBox "Not Found"
End If
End Sub
但是,如果将此函数粘贴到模块中并将其从工作表中调用为(在单元格C1中说出)=FindRange(A1,A1:A5)
代码只会为您提供找到的值的第一个实例,而忽略其余的
因此,你得到的结果是$ A $ 2 !!!
Function FindRange(FirstRange As Range, ListRange As Range) As String
Dim aCell As Range, bCell As Range, oRange As Range
Dim ExitLoop As Boolean
Set oRange = ListRange.Find(what:=FirstRange.Value, LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not oRange Is Nothing Then
Set bCell = oRange: Set aCell = oRange
Do While ExitLoop = False
Set oRange = ListRange.FindNext(After:=oRange)
If Not oRange Is Nothing Then
If oRange.Address = bCell.Address Then Exit Do
Set aCell = Union(aCell, oRange)
Else
ExitLoop = True
End If
Loop
FindRange = aCell.Address
Else
FindRange = "Not Found"
End If
End Function
我们需要从不同的角度来解决这个问题。
我们不再使用.FindNext,而是再次使用.Find直到我们得到所需的结果($ A $ 1:$ A $ 3)。请参阅下面的代码:
Function FindRange(FirstRange As Range, ListRange As Range) As String
Dim aCell As Range, bCell As Range, oRange As Range
Dim ExitLoop As Boolean
Set oRange = ListRange.Find(what:=FirstRange.Value, LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
If Not oRange Is Nothing Then
Set bCell = oRange: Set aCell = oRange
Do While ExitLoop = False
Set oRange = ListRange.Find(what:=FirstRange.Value, After:=oRange, LookIn:=xlValues, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not oRange Is Nothing Then
If oRange.Address = bCell.Address Then Exit Do
Set aCell = Union(aCell, oRange)
Else
ExitLoop = True
End If
Loop
FindRange = aCell.Address
Else
FindRange = "Not Found"
End If
End Function