Column A has a long string in it. I need to find if any of the 50 words in column B (1 word per row) are in each row in column A. After that, whichever word matched from column B I need the corresponding number in column C.
I've tried different VLookups, Match, and Index formulas with no luck. If I need to clarify the problem please let me know.
Edit: Here's an example:
Try something like this:
Add this formula in F2 and drag down:
=LOOKUP(2^50,SEARCH($C$2:$C$5,A2),$D$2:$D$5)
This is not an array formula.
Same concept, but using an array...
Public Function match_keyword2(CellVar As Range)
'initialize at zero
match_keyword2 = 0
Dim keyword_ARRAY(1 To 3) As String
keyword_ARRAY(1) = "blue"
keyword_ARRAY(2) = "green"
keyword_ARRAY(3) = "red"
For i = LBound(keyword_ARRAY) To UBound(keyword_ARRAY)
If InStr(CellVar.Value, keyword_ARRAY(i)) > 0 Then
match_keyword2 = i
Exit For
End If
Next i
End Function
...then modify the code to include your list of keywords.
You could try making a custom formula. Add this module to your excel file:
Public Function match_keyword(CellVar As Range)
'Insert a blank column
'add the excel function "=match_keyword(A1)"
'in it, you will see a number which represents the first matching keyword
If InStr(CellVar.Value, "blue") > 0 Then
match_keyword = 1
ElseIf InStr(CellVar.Value, "green") > 0 Then
match_keyword = 2
ElseIf InStr(CellVar.Value, "red") > 0 Then
match_keyword = 3
Else
'no match found
match_keyword = 0
End If
End Function
Modify the code to include all your keywords, and their corresponding number.
You can try below formula:
=INDEX(D$2:D$5,IF(SUM(IFERROR(SEARCH(C$2:C$5,A2),0))>0,MATCH(MAX(IFERROR(SEARCH(C$2:C$5,A2),0)),IFERROR(SEARCH(C$2:C$5,A2),0),0),NA()))
Entered in F2 as Array Formula by pressing Ctrl+Shift+Enter.
Result:
Related
I have a range of numbers and I need to identify if the first number of each cell is repeated anywhere in the corresponding row.
For example, in row 2 below, column 2 and column 3 both start with a 3. I know that if I do =LEFT(TRIM(cell)) to get just the first number but how do I find the rows that have repeated numbers in the row so row 1 isn't marked but row 2 is?
100|600|203|700| |
202|302|301|400|600|
Use a helper column with this as an array formula:
=SUMPRODUCT(--(COLUMN($A1:$E1)<>MATCH(INT($A1:$E1/100),INT($A1:$E1/100),0)))>0
Being an array formula it must be confirmed with Ctrl-Shift-Enter instead of Enter when exiting edit mode. If done correctly then Excel will put {} around the formula.
Consider the following UDF():
Public Function AnyDups(rng As Range) As Boolean
Dim valu() As String
Dim i As Long, L As Long
L = rng.Count
ReDim valu(1 To L)
AnyDups = False
If L = 1 Then Exit Function
i = 1
For Each r In rng
valu(i) = Left(r.Value, 1)
i = i + 1
Next r
For i = 1 To L - 1
v = valu(i)
For j = i + 1 To L
If v = valu(j) Then AnyDups = True
Next j
Next i
End Function
For example:
The code just loops through the possible combinations of left-most characters in the cells.
It should work with either text or numeric data.
One way to do it would be to use this formula as a basis:
=IF(ISERROR(FIND(LEFT(TRIM(A1),1),B1)),FALSE,"Row "& ROW(A1))
Depending on how you want to check your row, you can adapt it. You could either have one formula to check one cell (Lock the A1 reference and drag right) - which would allow you to know where the match is but take more space on the sheet.
Or, if you don't have too many cells to check in each row, you could concatenate all cells in the same formula:
=IF(ISERROR(FIND(LEFT(TRIM(A1),1),B1&C1&D1&E1)),FALSE,"Row "& ROW(A1))
I'm sure Gary's Student will have a more elegant answer though!
I need help in this situation:
Some hundreds of rows of column A is filled in random order with color names (white, blue, green, yellow, red). I need a formula in column B that shows the row number of the previous occurrence of that color in column A.
Example:
A B
white 0 or not found
yellow 0 or not found
yellow 2
green 0 or not found
white 1
yellow 3 (note: not `2`, which is the first occurrence, `3` is the last)
Please take a look at this formula. It will work but it requires your data to begin in row 2:
Place this formula in cell B2:
=IFERROR(LOOKUP(2,1/(A$1:A1=A2),ROW($1:1)),0)
It is NOT an array formula, so just confirm it normally, with the ENTER key.
Now copy B2 down as far as you need.
You could use a VBA function. If you haven't done VBA, you might just have to look up how to create a new module.
In a new module, paste this code:
Public Function FindColorPosition(m_Range As Range) As String
FindColor = "not found"
If m_Range.Row = 1 Then
Exit Function
End If
Dim i As Integer
For i = m_Range.Row - 1 To 1 Step -1
If m_Range.Value = Range("A" & i).Value Then
FindColor = Str(i)
Exit Function
End If
Next
End Function
Then, in cell B1 type =FindColorPosition(A1)
Then, in cell B2 type =FindColorPosition(A2)
and so on...
You will either get not found or the row in which that color was last seen.
I have two columns into two separate sheets. In the first, C1, I have 1000 rows containing text, in the second column C2 I have 2000 rows also containing text.
What I need to do is to select all the C2 rows which contain at least (exactly) all the text contained in any of the C1 rows.
For instance, suppose data are like this:
C1 C2
Eval 1 Eval 101 doc
Eval 1 Eval 1 project
Eval 100 Eval 1 doc
Ev 1 Eval 19
Eval1 Ev 2
In the end I would like to select only the following cells in the second sheet:
C2
Eval 1 doc
Eval 1 project
I am not very familiar with Excel, but I produced the following function:
=IF(ISNUMBER(FIND(<C1 cell>, <C2 cell>)),"OK", "Not OK")
and then it should just be a matter of filtering data according to "OK".
The problem is that the function works only for single C1 values, but not if I select the entire C1 column as I need to..
I also thought to use VLOOKUP, but then what I need is not the C2 values perfectly matching with C1 values but, as I said before, the ones that at least contain the entire text of the C1 cells..
Any suggestion would be highly appreciated,
Stefano
Ok, try this, it's not great, but I think it will work for you:
Add the following code to your workbook in a standard module, and save the workbook
Public LookInCollection As New Collection
Function SetUpCollection(range)
'Load data into collection
On Error Resume Next
For Each Cell In range
LookInCollection.Add 1, Cell.Text
Next
On Error GoTo 0
End Function
Function MatchValue(Value)
Dim ValueArray As Variant
Dim Lenght As Long
ValueArray = Split(Value, " ")
'Loop String backwars remving words each time
For i = 0 To UBound(ValueArray)
If InCollection(Left(Value, Len(Value) - Lenght)) Then
MatchValue = 1
Exit Function
End If
Lenght = Len(ValueArray(UBound(ValueArray) - i)) + 1
Next
MatchValue = 0 'Cound not match
End Function
Private Function InCollection(Key) As Variant
On Error Resume Next
InCollection = LookInCollection(Key)
End Function
Next on the page with column 2 on it add one formula like this
=SetUpCollection(Column1_Range)
then add the forumla next to each cell in C2,
=MatchValue(ReftoCelltoCheck)
Update based on comment
The code has 3 parts. The first function builds a collection, that is used by the main function, that's why it's only used once. The last function just checks to see if the key is in the collection.
The second function does the work. It gets the value to check and loads each word in to an array, this is the split function. The for loop works backwards thought the value, removing words from the original value and checking this new value against the keys in the collection. A match returns 1 and we exit the function, else keep going until all the words are checked.
After 3 hours of searching I still didn't find an answer, here is what I am trying to do:
I am trying to fill with green any row that has WBS in it and with Red any row that has ACT in it and Blue any row that has EPR in it. It works for the first formula then when I try to add the second one every thing get messed up.
what i have understood is that you need to search a keyword in a row and if its found in any cell of that row then color it.
May be we can do it with conditional formatting but i have another idea. We can create a simple search function in Excel VBA. Something like this:
=search_row(A1:F1,"EPR")
The function will return 1 if EPR is found in any cell of specified row. Now if you create two different columns at the end of data columns, name first with WPS and second with EPR and write this function in it. Like
G1 =search_row(A1:F1,"WPS")
H1 =search_row(A1:F1,"EPR")
Drag it to end. Now sort the columns. First for WPS from higher to lower. Then color all rows having 1 in a single select. Similarly do the same with EPR (H1) column.
To use this function you can download the macro file from the following URL:
http://asimishaq.com/myfiles/SearchHighlight.xlsm
Now to run it first of all enable macros, and then re-open your data file and then open this macro file. As long as this macro file is opened you can use this function. Following is the VBA code if you want to create the macro yourself:
Function search_row(sRow As Range, Keyword As String)
Dim i As Integer
Dim Found As Integer
For i = 1 To sRow.Columns.Count
If InStr(1, LCase(sRow.Cells(1, i)), LCase(Keyword)) > 0 Then
search_row = 1
End If
Next
End Function
I had a go at making a function similar to asim-ishaq to determine if your search term exists in the row for fun :) then tried to apply it to highlighting rows, turns out I dont know how to use conditional formatting very well! Figured it out in the end, hopefully I've explained it well enough.
With this you will have to have (one) extra column at the end of your data to contain the result.
It might be possible to not require the extra column by putting the function inside the conditional formatting, however I couldn't get it to work (didn't try very hard). This isn't a great loss as it's much simpler to edit the formula if its on the workbook, instead of having to go through each conditional rule to edit it, should you need to edit it in the future.
To get the formatting to work you will need to create a number of rules (one per keyword)
You want to create a rule of the type shown below, in the formula box you need something along the lines of: =INDIRECT("D" & ROW())=0 where D is the column containing the result of the function below and 0 is the index of the keyword you're highlighting.
In my example, the formula in the D Column is: =SearchRow(An:Cn,"ABS","KBS","JBS") (where n is the row the formula is on)
Set the formatting as desired then press OK, when you return to the rule manager you will need to update the Applies to value, which should be a range that covers all the data you want to highlight. In my example it was $A$1:$C$3
My function below takes 2+ Arguments, The first is the range to search. The second (and any subsequent ones) are search terms.
The function will return a number. -1 for no matches and 0+ for the found search term. The number depends on the position in the arguments.
A1 = "ABS"
B1 = "SBA"
A2 = "SBA"
B2 = "ABS"
A3 = ""
B3 = ""
C1 = "=SearchRow(A1:B1, "ABS", "SBA")"
C2 = "=SearchRow(A2:B2, "ABS", "SBA")"
C3 = "=SearchRow(A3:B3, "ABS", "SBA")"
C1 > 0
C2 > 1
C3 > -1
The function will always return the first result, searching left to right comparing each cell to the Keywords in order. Using my example, if a cell contained "SBA ABS" the result would be 0 (for ABS). I guess your cells will probably only contain one keyword though so this shouldn't be a problem?
Public Function SearchRow(ByVal Row As Range, ParamArray Keyword() As Variant) As Integer
Dim Column As Integer
Dim Value As String
Dim Index As Integer
Dim Result As Integer
For Column = 1 To Row.Columns.Count
Value = LCase(Row.Cells(1, Column))
Result = -1
For Index = LBound(Keyword) To UBound(Keyword)
If InStr(1, Value, LCase(Keyword(Index))) > 0 Then
Result = Index
Exit For
End If
Next Index
If Result > -1 Then
Exit For
End If
Next Column
SearchRow = Result
End Function
I've got a spreadsheet full of names and peoples' roles, like the one below:
Role Name Change
1 A Yes
2 A No
5 A N/Ap
1 B Yes
3 B No
2 C Yes
4 C No
I have to come up with a spreadsheet like the one below:
1 2 3 4 5 6
A Yes
B
C
Basically, it should retrieve the information from the first spreadsheet and be layed out clearly on the second one.
There are way too many names and roles to do it manually. VLMOVE won't work and I've tried MATCH and INDEX.
Alternative to #RocketDonkey (but thanks for more complete desired result!) could be to string together Role and Name (say in a column inserted between B & C in Sheet1 [because I think OP wants a separate sheet for the results]):
C2=A1&B2 copied down as required
then use a lookup in Sheet2!B2:
=IFERROR(VLOOKUP(B$1&$A2,Sheet1!$C$2:$D$8,2,FALSE),"")
copied across and down as required.
This assumes the grid for the results (as in question) has been constructed (and that there are 7 rows with data - adjust $8 as necessary otherwise.)
Agree with #Melanie that if you can force your data into a structure that can be interpreted as numbers (1 being yes, 0 being false, for example), Pivot tables are far and away the easiest way (since they will display numbers as the values - not the text). *(see below)
If you want to display arbitrary text, you could try this:
=IF(
SUMPRODUCT(--($A$2:$A$8=F$1),--($B$2:$B$8=$E2),ROW($A$2:$A$8))=0,"",
INDEX(
$A$1:$C$8,
SUMPRODUCT(--($A$2:$A$8=F$1),--($B$2:$B$8=$E2),ROW($A$2:$A$8)),
3))
This checks to see if the SUMPRODUCT of the three columns totals 0 (which will happen when no combo of x/y is matched (like Name: C, Role: 5, for instance), and if so, it returns "". Otherwise, it returns the value in column Value.
*A ‘pivot table option’ would be to represent the Change as a number (eg as formula in D2 copied down). Then create a pivot table from (in the example) A1:D8, with fields as shown. Copy the pivot table to a different sheet with Paste Special/Values (though shown in F11:K15 of same sheet in example). Then in that other sheet select row starting with Name A and as far down as required, Replace -1 with No, 1 with Yes and 0 with N/Ap.
AMENDED
You can use array formulas to reorganize your table, without having to change the its structure. Assuming the data is in the range A2:C8 on Sheet1 and the result table is to be in range A1:G4 on Sheet2, the following formula would be the first entry (role 1 and name A) in the result table.
=IFERROR(INDEX(Sheet1!$A$2:$C$8,MATCH(B$1&$A2,Sheet1!$A$2:$A$8&Sheet1!$B$2:$B$8,0),3),"-")
The MATCH formula returns the row number in which the role/name combination 1A occurs. The INDEX function returns the contents of the cell at the row number found by the MATCH formula and the column number 3, i.e., the Change column of your data table. The IFERROR returns "-" if the role/name combination is not in the data table.
Be sure to enter the formula using the Control-Shift-Enter key combination. Then copy the formula to the remaining cells of the result table.
The data table on Sheet1:
The result table on Sheet2:
Well since there's Excel-VBA tag, thought it would complete the solutions types by adding one in VBA :) The following code is not elegant, in any case you need to use code base, give it a try :)
Code:
Option Explicit
Public Sub sortAndPivot()
Dim d As Object
Dim ws As Worksheet
Dim sourceArray As Variant, pvtArray As Variant, v As Variant
Dim maxRole As Long
Dim i, j, k, m As Integer
Set d = CreateObject("Scripting.Dictionary")
Set ws = Worksheets("Sheet3") '-- set according to your sheet
'-- you could enhance by using an input box to select the range
sourceArray = Application.WorksheetFunction.Transpose(ws.Range("B3:D9").Value)
'-- max role number
maxRole = Application.WorksheetFunction.Max(ws.Range("B3:B9"))
'-- find unique name list
For i = LBound(sourceArray, 2) To UBound(sourceArray, 2)
If Not d.exists(sourceArray(2, i)) Then
d.Add sourceArray(2, i), i
End If
Next i
ReDim pvtArray(d.Count, maxRole)
pvtArray(0, 0) = "Name"
'-- add unique names from dictionary
j = 1
For Each v In d.keys
pvtArray(j, 0) = v
j = j + 1
Next
'-- add unique Role number list
For i = UBound(pvtArray, 2) To LBound(pvtArray) + 1 Step -1
pvtArray(0, i) = i
Next i
'-- sort into the correct positions
For k = LBound(pvtArray, 1) + 1 To UBound(pvtArray, 1)
For m = LBound(pvtArray, 2) + 1 To UBound(pvtArray, 2)
For i = LBound(sourceArray, 2) To UBound(sourceArray, 2)
If pvtArray(k, 0) = sourceArray(2, i) Then
If pvtArray(0, m) = sourceArray(1, i) Then
pvtArray(k, m) = sourceArray(3, i)
End If
End If
Next i
Next m
Next k
'Output the processed array into the Sheet in pivot view.
Range("F2").Resize(UBound(pvtArray) + 1, _
UBound(Application.Transpose(pvtArray))) = pvtArray
Set d = Nothing
End Sub
Results:
There is another way to go about it without VBA. If you create another column that concatenates the first two in the first spreadsheet, like so:
Role Name Change CheckColumn
1 A Yes 1A
2 A No 2A
5 A N/Ap 5A
1 B Yes 1B
3 B No 3B
2 C Yes 2C
4 C No 4C
Then you can use the Offset and Match functions together to find the change in the 2nd sheet. So assuming your data is laid from cell A1, the formula in cell B2 would be:
=iferror(offset(Sheet1!$A$1,match(B$1&$A2,sheet1!$D:$D,0),2),"")
Alternatively, if you put the concatenated column in sheet1 before the role column, you can use vlookup in sheet2, with the formula being:
=iferror(vlookup(B$1&$A2,sheet1!$A:$D,4,false),"")