VLOOKUP Closest Match Not Close Enough

R

Ronster

I'm comparing one string array with another using VLOOKUP. About half
the list matches exactly if I use FALSE in the Range_Lookup. On the
items that don't match I used TRUE in the Range_Lookup but found it
doesn't get the closest match. See example:

Test Table Array
AAABBBCCC
AAACCCCCC
AAACCCDDD

Lookup Value = AAACCCCC

VLOOKUP returns 1st item in Table (AAABBBCCC) ????????????

Of course item 2 (AAACCCCCC) is the better match but VLOOKUP doesn't
see it that way.

Does anyone know of a way around this problem? Maybe a character by
character match function that returns the item that matchs the most
number of correct characters?

Thanks in advance.
 
J

Jim Thomlinson

When you use true, the list that your are looking up into must be sorted,
otherwise it may return the wrong value.
 
N

Niek Otten

AAACCCCCC is greater than AAACCCC so Excel returns the one before.
If there is not too much variation in the length of the string you could
introduce some extra columns in your table, derived from the original one,
wit fewer characters.
In your formula you could choose the column to look in, depending on the
length of your search argument.
To find out the length of your search argument: =LEN(A2)
To get a smaller column: =LEFT(A1,LEN(A1)-1)
 
C

Charlie

The list is sorted, but the lookup value has one less "C", therefore, having
fewer characters than AAABBBCCC makes it return the first value in the lookup
list, no?
 
R

Ronster

Are any of you aware of a function that does a character by character
match of a string to an array no matter what the length of the string?
If I don't get an exact match using VLOOKUP what I really want is the
item that matches the most number of characters in the string.
 
R

Ronster

Thanks Niek but I should have mentioned before my seach strings vary
from 4 to 52 chars and that's just in list I'm presently using. Other
list I need to search may be more or less so creating a column for each
search length gets a little large. Also in some search strings only a
few characters actually match anything in the table array so the seach
string could be 45 characters but only the first 3 characters match to
something in the table array. I think a function would work better.
 
J

Jim Thomlinson

Sorry about that I thought they were the same length... You will need to
parse the strings into smaller strings (as per Niek's suggestion) and play
around to get what you want. This is one of those cases where what appears to
be the simplest thing is the most difficult to accomplish.
 
J

Jim Thomlinson

The logic on this is very ugly because it is fuzzy. To come up with one
function that fits all of the possible circumstances will be very difficult.
For example what to do if we are trying to match a 7 character string to
items in the list and:

One possible match has all 7 characters but not in a row.
Another possible matches 6 charaters starting in the second position
Another possible matches the first 5 characters exactly
Another matches the last 5 characters exactly

Which ONE should the function return??? There needs to be very definite
rules in place that work for ALL cases.
 
K

Kleev

No warranties, but this function appears to do what you are asking (based on
the tests I threw at it.)

Function MatchChar(myString As String, myRng As Range) As Variant
Dim L As Integer, L2 As Integer
Dim i As Integer
Dim cell As Range
Dim TestChar As String, CellVal As String, CellChar As String
Dim NotFound As Boolean
Dim MatchCnt As Integer, PrevMatchCnt As Integer
Dim MatchRowIndex As Long
Dim RowIndex As Integer

PrevMatchCnt = 0
RowIndex = 0
L = Len(myString)
If myString = "" Then
MatchChar = CVErr(2042)
Else
For Each cell In myRng
MatchCnt = 0
RowIndex = RowIndex + 1
NotFound = False
CellVal = cell.Value
L2 = Len(CellVal)
i = 1
Do Until i > L Or i > L2 Or NotFound
TestChar = Mid(myString, i, 1)
CellChar = Mid(CellVal, i, 1)
If TestChar = CellChar Then
MatchCnt = MatchCnt + 1
Else
NotFound = True
End If
i = i + 1
Loop
If MatchCnt > PrevMatchCnt Then
MatchRowIndex = RowIndex
PrevMatchCnt = MatchCnt
End If
Next cell
If PrevMatchCnt > 0 Then
MatchChar = MatchRowIndex
Else
MatchChar = CVErr(2042)
End If
End If
End Function

Here is some data I threw at it. Data range is A2:B6. Formula in C2
(copied down through C11) is: =MatchChar(D2,$A$2:$A$6)
Using the function with the Index function for rows 12 - 22 (starting from
where the word Index -----------> is) formula is:
=INDEX($A$2:$B$6,MatchChar(D12,$A$2:$A$6),2)

AAABBBCCC B2 2 AAACCCCC
AAACCCCCC B3 5 mou
AAACCCDDD B4 #N/A
BBBABCX B5 1 AAABB
mouse B6 2 AAACCCCC
4 B
1 AAAB
1 A
3 AAACCCD
#N/A aaa
Index ---------------> B2 AAA
B3 AAACCCCC
B6 mou
#N/A
B2 AAABB
B3 AAACCCCC
B5 B
B2 AAAB
B2 A
B4 AAACCCD
#N/A aaa
 
R

Ronster

Thanks Kleev. Here's something I threw together and it seems to work
pretty well.

Function ExactCharMatch(MySearchStr As String, Rng As Range) As String
' Function does a character by character search to determine which
' range item matches the most search characters from left to right.
' With range sorted in ascending order only one pass is needed to
determine best match.
' Use as-is or change as needed.

Dim MyRange As Range, MySearchStrLen As Integer, I As Integer, CharPos
As Integer
Dim LastGoodMatch As String

MySearchStrLen = Len(MySearchStr)

CharPos = 1

For Each MyRange In Rng
Do While Left(MySearchStr, CharPos) = Left(MyRange, CharPos)
'MsgBox Left(MySearchStr, CharPos) + " = " + Left(MyRange,
CharPos)
If CharPos >= MySearchStrLen Then
Exit For
End If
CharPos = CharPos + 1
LastGoodMatch = MyRange
Loop
If Left(MySearchStr, CharPos - 1) <> Left(MyRange, CharPos - 1)
Then
Exit For
End If
Next

ExactCharMatch = LastGoodMatch

End Function
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top