Column D contains the substring to look for, which could be anywhere in the search field of column A. Column E contains the value to replace the content of column A with. See the results in Column B. Can anyone help me out?
After implementing suggested solution
If you are fine with it, I suggest a modification to the arrangement.
Arrange the lookup values as in the image, in columns F, G and H and the replace values in the next corresponding row. You would need 3 helper columns, (since you have 3 lookup values). Column B, C and D are helper columns.
Enter the below formula in column B, B1,
=IFERROR(IF(MATCH("*"&F$1&"*",$A1,0),F$2),"")
Just drag it to the bottom throughout the range, and then drag it to right upto column E.
Column F is your actual output. Enter the formula in column F,
=B1&C1&D1
and drag it down. Hope this helps. Let me know if you need anything else.
This works, but is not very elegant and won't easily scale.
=CONCATENATE(REPT($E$1,COUNTIF(A1,"*"&$D$1&"*")),REPT($E$2,COUNTIF(A1,"*"&$D$2&"*")),REPT($E$3,COUNTIF(A1,"*"&$D$3&"*")))
It's series of REPT(Replacement,COUNTIF(Values,*Labels*)). The *'s around the search allow it to be wildcard, essentially making the COUNTIF's flags of if the element is included or not. We then repeat the replacement value the number of times the countif is present (which in the example will always be 1), and then concatenate the results.
I have created a VB script to solve this:
Sub DetermineFeatures()
Dim featureLabel As String
Dim testString As String
testString = "FEAT_EMV_L4, Team_1, Team_IBM"
Dim stringValue As Variant
Dim lookupRange As Range
Set lookupRange = Worksheets("LookupTable").Range("A1:B100")
Dim outputWorksheet As Worksheet
Set outputWorksheet = Worksheets("Output")
Dim feature As String
Dim rowIndex As Long
For Each cell In Worksheets("Original").Columns("O").Cells
rowIndex = cell.Row
cellValue = WorksheetFunction.Trim(cell.Value)
For Each stringValue In Split(cellValue, ",")
If InStr(stringValue, "LABEL_") Then
featureLabel = Trim(stringValue)
' Call the Vlookup function to look up the actual feature name
for the supplied label. This
' returns the value from the second column of the range within
the LookupTable worksheet.
feature = Application.WorksheetFunction.VLookup(featureLabel,
lookupRange, 2, False)
outputWorksheet.Cells(rowIndex, 1) = feature
If Not IsEmpty(featureLabel) Then Exit For
End If
Next
Next cell
End Sub
Related
I am looking for reverse vlookup with more than 255 characters in Excel VBA.
This is the formula based one which I took from this website.
=INDEX(F2:F10,MATCH(TRUE,INDEX(D2:D10=A2,0),0))
I have try to convert it in VBA. Here below sample code
Sub test()
'concat
Range("i1") = WorksheetFunction.TextJoin(" ", True, Range("g1:h1"))
'lookup
Sal1 = Application.WorksheetFunction.Index(Sheets("sheet1").Range("a1:a2"), Application.WorksheetFunction.Match(True, Application.WorksheetFunction.Index(Sheets("sheet1").Range("i1:i1") = Range("i1").Value, 0), 0))
'=INDEX($W$3:$W$162,MATCH(TRUE,INDEX($W$3:$W$162=U3,0),0))
End Sub
It works well but it didn't when i change the range("i1:i1") to range("i1:i2")
I'm not sure what that worksheet formula does that =INDEX(F2:F11,MATCH(A2,D2:D11,FALSE)) doesn't do.
This part Index(Sheets("sheet1").Range("i1:i2") = Range("i1").Value, 0) is comparing a 2-d array to a single value, which should result in a Type Mismatch error. Whenever you reference a multi-cell range's Value property (Value is the default property in this context), you get a 2-d array even if the range is a single column or row.
You could fix that problem with Application.WorksheetFunction.Transpose(Range("D1:D10")) to turn it into a 1-d array, but I still don't think you can compare a 1-d array to a single value and have it return something that's suitable for passing into INDEX.
You could use VBA to create the array's of Trues and Falses, but if you're going to go to that trouble, you should just use VBA to do the whole thing and ditch the WorksheetFunction approach.
I couldn't get it to work when comparing a single cell to a single cell like you said it did.
Here's one way to reproduce the formula
Public Sub test()
Dim rFound As Range
'find A2 in D
Set rFound = Sheet1.Range("D1:D10").Find(Sheet1.Range("A2").Value, , xlValues, xlWhole)
If Not rFound Is Nothing Then
MsgBox rFound.Offset(0, 2).Value 'read column f - same position as d
End If
End Sub
If that simpler formula works and you want to use WorksheetFunction, it would look like this
Public Sub test2()
Dim wf As WorksheetFunction
Set wf = Application.WorksheetFunction
MsgBox wf.Index(Sheet1.Range("F2:F11"), wf.Match(Sheet1.Range("A2").Value, Sheet1.Range("D2:D11"), False))
End Sub
Function betterSearch(searchCell, A As Range, B As Range)
For Each cell In A
If cell.Value = searchCell Then
betterSearch = B.Cells(cell.Row, 1)
Exit For
End If
betterSearch = "Not found"
Next
End Function
i found this code from above link and it is useful for my current search.Below examples i try to get value..
Kindly consider Row 1 to 5 as empty for A and B column because my table always start from Row 6
Row
A Column
B Column
6
54
a
7
55
b
8
56
c
VBA Code:
Sub look_up ()
Ref = "b"
look_up = betterSearch(Ref, Range("B6:B8"), Range("A6:A8"))
End Sub
it show Empty while use Range("B6:B8"), Range("A6:A8")
but when changing the range from B6 and A6 to B1 and A1 (Range("B1:B8"), Range("A1:A8") )it gives the value...
My question is "can get the values from desired range"
Expressing matches via VBA
I like to know if there (are) any possibilities to convert this formula.
=INDEX(F2:F10,MATCH(TRUE,INDEX(D2:D10=A2,0),0))
So "reverse VLookUp" in title simply meant to express the (single) formula result via VBA (btw I sticked to the cell references in OP, as you mention different range addresses in comments).
This can be done by simple evaluation to give you a starting idea:
'0) define formula string
Dim BaseFormula As String
BaseFormula = "=INDEX($F$2:$F$10,MATCH(TRUE,INDEX($D$2:$D$10=$A2,0),0))"
'1) display single result in VB Editor's immediate
Dim result
result = Evaluate(BaseFormula)
Debug.Print IIf(IsError(result), "Not found!", result)
On the other hand it seems that you have the intention to extend the search string range
from A2 to more inputs (e.g. till cell A4). The base formula wouldn't return a results array with this formula,
but you could procede as follows by copying the start formula over e.g. 3 rows (note the relative address ...=$A2 to allow a row incremention in the next rows):
'0) define formula string
Dim BaseFormula As String
BaseFormula = "=INDEX($F$2:$F$10,MATCH(TRUE,INDEX($D$2:$D$10=$A1,0),0))"
'2) write result(s) to any (starting) target cell
'a)Enter formulae extending search cells over e.g. 3 rows (i.e. from $A2 to $A4)
Sheet3.Range("H2").Resize(3).Formula2 = BaseFormula
'b) optional overwriting all formulae, if you prefer values instead
'Sheet3.Range("H2").Resize(3).Value = Tabelle3.Range("G14").Resize(3).Value
Of course you can modify the formula string by any dynamic replacements (e.g. via property .Address(True,True,External:=True) applied to some predefined ranges to obtain absolute fully qualified references in this example).
Some explanations to the used formulae
The formula in the cited link
=INDEX(F2:F10,MATCH(TRUE,INDEX(D2:D10=A2,0),0))
describes a way to avoid an inevitable #NA error when matching strings with more than 255 characters directly.
Basically it is "looking up A2 in D2:D10 and returning a result from F2:F10" similar to the (failing) direct approach in such cases:
=INDEX(F2:F11,MATCH(A2,D2:D11,FALSE))
The trick is to offer a set of True|False elements (INDEX(D2:D10=A2,0))
which can be matched eventually without problems for an occurence of True.
Full power by Excel/MS 365
If, however you dispose of Excel/MS 365 you might even use the following much simpler function instead
and profit from the dynamic display of results in a so called spill range.
That means that matches can be based not only on one search string, but on several ones (e.g. A1:A2),
what seems to solve your additional issue (c.f. last sentence in OP) to extend the the search range as well.
=XLOOKUP(A1:A2,D2:D10,F2:F10,"Not found")
I link Get a first column range from a range in Excel VBA to undestand the content.
My question is:
is it possible to know the number of the column if I know the name of the column? for example: I would like know if the column named "mycolumn" is the numer 1 or 2 or 3 or x... in the table named "mytable"
Regards
Range("mycolumn").cells(1,1).column will give you the number of the first column in a range called "mycolumn"
EDIT: My Bad - I didn't see this was a named column in a table - Axel's answer in comments is correct.
... if the column named "mycolumn" is the numer 1 or 2 or 3 or x... in the table named "mytable".
To find the ordinal position of a column within its parent table, you need to look only at the range of the table, not te worksheet that the table resides on.
On the worksheet,
=MATCH("mycolumn", mytable[#Headers], 0)
In the following image, the above formula returns 3.
In VBA as a function,
Option Explicit
Sub main()
Debug.Print ColumnNdx("sheet2", "mytable", "mycolumn")
End Sub
Function ColumnNdx(wsnm as string, tblnm As String, colnm As String)
Dim m As Variant, hdrrng As Range
ColumnNdx = CVErr(xlErrNA)
Set hdrrng = ThisWorkbook.Worksheets(wsnm ).ListObjects(tblnm).HeaderRowRange
m = Application.Match(colnm, hdrrng, 0)
If Not IsError(m) Then ColumnNdx = CLng(m)
End Function
The above function returns 3.
First time posting for me and hoping to get some help with VBA for selective hardcoding.
I currently have a column into which a formula is set which returns either blank or a variety of text strings (the status of our company's orders).
I need to make a macro that looks into all the cells of that column and copy/pastes as value into that same cell only if the formula in that cell returns text string "Received". It should not affect the other cells where the formula is returning either blank or a different text string.
Would really appreciate your help. Please let me know if you need more info.
Thanks in advance,
Olivier
Put the following in the VBA project of your workbook:
Option Compare Text
Sub replaceThem()
Dim r As Range
Dim c
Set r = Range("B1:B3") ' use the actual range here
For Each c In r
If c.Value = "Received" Then c.Formula = "Received"
Next
End Sub
This will do what you asked. c.Value returns the value of the formula in the cell c, c.Formula replaces the formula. The Option Compare Text makes the comparison case-insensitive.
I would like to do a vertical lookup for a list of lookup values and then have multiple values returned into columns for each lookup value. I actually managed to do this after a long Google search, this is the code:
=INDEX(Data!$H$3:$H$70000, SMALL(IF($B3=Data!$J$3:$J$70000, ROW(Data!$J$3:$J$70000)-MIN(ROW(Data!$J$3:$J$70000))+1, ""), COLUMN(A$2)))
Now, my problem is, as you can see in the formula, my lookup range contains 70,000 rows, which means a lot of return values. But most of these return values are double. This means I have to drag above formula over many columns until all lookup values (roughly 200) return #NUM!.
Is there any possible way, I guess VBA is necessary, to return the values after duplicates have been removed? I'm new at VBA and I am not sure how to go about this. Also it takes forever to calculate having so many cells.
[Edited]
You can do what you want with a revised formula, not sure how efficient it will be with 70,000 rows, though.
Use this formula for the first match
=IFERROR(INDEX(Data!$H3:$H70000,MATCH($B3,Data!$J3:$J70000,0)),"")
Now assuming that formula in in F5 use this formula in G5 confirmed with CTRL+SHIFT+ENTER and copied across
=IFERROR(INDEX(Data!$H3:$H70000,MATCH(1,($B3=Data!$J3:$J70000)*ISNA(MATCH(Data!$H3:$H70000,$F5:F5,0)),0)),"")
changed the bolded part depending on location of formula 1
This will give you a list without repeats.....and when you run out of values you get blanks rather than an error
Not sure if you're still after a VBA answer but this should do the job - takes about 25 seconds to run on my machine - it could probably be accelerated by the guys on this forum:
Sub ReturnValues()
Dim rnSearch As Range, rnLookup As Range, rnTemp As Range Dim varArray
As Variant Dim lnIndex As Long Dim strTemp As String
Set rnSearch = Sheet1.Range("A1:A200") 'Set this to your 200 row value range
Set rnLookup = Sheet2.Range("A1:B70000") 'Set this to your lookup range (assume 2
columns)
varArray = rnLookup
For Each rnTemp In rnSearch
For lnIndex = LBound(varArray, 1) To UBound(varArray, 1)
strTemp = rnTemp.Value
If varArray(lnIndex, 1) = strTemp Then
If WorksheetFunction.CountIf(rnTemp.EntireRow, varArray(lnIndex, 2)) = 0 Then 'Check if value exists already
Sheet1.Cells(rnTemp.Row, rnTemp.EntireRow.Columns.Count).End(xlToLeft).Offset(0, 1).Value =
varArray(lnIndex, 2)
End If
End If
Next Next
End Sub
I need to write a macro that will find the cell range based on a value. A column will have the same value in a row, I need to find out what is the first and last column that has the same value in a row.
So the macro needs to find that "Jill Cross" range is a4 to a9
So far I don't have much, got a way to find the first occurrence of a value
Function GetFirstCell(CellRef As Range)
Dim l As Long
l = Application.WorksheetFunction.Match(CellRef.Value, Range("A1:A10000"), 0)
GetFirstCell = l
End Function
Now I need to loop through the next rows somehow to return the last row of an occurrence
If you have your first cell in a sorted list, a countif function will give you the last cell easily.
Function GetFirstCell(CellRef As Range) as long
Dim l As Long
l = Application.WorksheetFunction.Match(CellRef.Value, Range("A1:A10000"), 0)
GetFirstCell = l
End Function
function GetLastCell(cellRef as range, lFirstCell as long)
Dim l As Long
l = Application.WorksheetFunction.countif(Range("A1:A10000"), CellRef.Value)
GetLastCell = lFirstCell+l-1
End Function
This will work though it has its limitations (for example if the names aren't sorted and the name you are looking for is separated across multiple places in your range...). Of course you need to replace the ranges with those you want to check and "bob" with whatever name you are looking for. Also, the column is static so you may want to alter that part. This is an array formula so you will need to press [ctrl]+[shift]+[enter] in the formula bar to execute it.
="A"&MIN(IF(ROW(A1:A6)*(A1:A6="bob")=0, 99999999, ROW(A1:A6)*(A1:A6="bob")))&":A"&MAX(SI(ROW(A1:A6)*(A1:A6="bob")=0, -99999999, ROW(A1:A6)*(A1:A6="bob")))