Finding previous occurence - excel

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.

Related

How do I input values in the Excel model without doing it manually?

I have the feeling that my previous question is being misunderstood. Therefore, I will do this as follows. What I would like is the following:
In this picture you see that the input is 4 in cell B1. This B1 cell is used as an input for a complicated model in a different sheet. The output of that model is linked to B2. I do not want to modify the complicated model on the other sheet (this part is required).
Now I would like to create a table like this:
So when the input is 4, the output from the model in the other sheet is 1. Now I can do this manually for 1, 2 and 3, by simply replacing the number written at B2 (which is 4) to 1 and check its output. Let’s observe what our complicated model gives us:
Apparently it gives us a 9, so I fill 9 in the F2. Now this is currently not a problem, since my table goes from 1 to 4. But how do I automate this? For example if I go from 1 to 100.
The problem is, you cannot touch or simplify the model on the other sheet.
How would one do this in VBA or do this in Excel itself?
I think you might have an issue in your explanation. Your example is A1 = 1, B1 = A1+5, despite saying it's A1 & A2. You are saying "Columns C & D" when I believe you mean "Rows 3 & 4).
If I understand your plight correctly, you are looking to drag down (auto-fill) the formula to the subsequent rows. You can do this with VBA, but you can do it without.
Provided you have data in the first column (A) as far as you would like the formula to travel, you can double-click from the lower right hand corner of the formula-reference cell and it will fill down. You could also drag the formula down by clicking and holding the lower right hand corner of the formula-reference cell.
You will know if you have the lower right hand corner if your cursor changes from from a "+" that is relatively large (with interior color) to a "+" that is relatively small (with no interior color... all black).
You will need to ensure that you have relative references when doing this, or ensure that your non-relative references are what you want. This is more than your question asked, but is important when doing this type of work.
See this:
Range("B1").Formula = A1 + 5
In this formula, A1 is relative to B1 by an off-set of -1 column. Every cell that the formula is pasted or dragged into will perform the formula with the cell that is -1 column relative.
You can add specifics to columns, rows, or cells, by use of "$". Say you have your example, and want to show the formula in Column C. There're 3 scenarios by using "$" which have different outcomes:
Fully relative, the dragged-formula will automatically designate the adjacent column.
Range("B1").Formula = A1 + 5
Range("C1").Formula = B1 + 5
Range("B2").Formula = A2 + 5
Range("C2").Formula = B2 + 5
If the "$" is in front of the column in the formula, the-dragged will "lock" the column, so when the formula is dragged, the column stays the same, but the row number will change.
Range("B1").Formula = $A1 + 5
Range("C1").Formula = $A1 + 5
Range("B2").Formula = $A2 + 5
Range("C2").Formula = $A2 + 5
If the "$" is in front of the row in the formula, the-dragged will "lock" the row, so when the formula is dragged, the row stays the same, but the column will change.
Range("B1").Formula = A$1 + 5
Range("C1").Formula = B$1 + 5
Range("B2").Formula = A$1 + 5
Range("C2").Formula = B$1 + 5
If the "$" is in front of the each the column and row in the formula, the-dragged will "lock" both. When the formula is dragged, the referenced-cell stays the same.
Range("B1").Formula = $A$1 + 5
Range("C1").Formula = $A$1 + 5
Range("B2").Formula = $A$1 + 5
Range("C2").Formula = $A$1 + 5
Hopefully that helps and is what you're looking for!
So you want to automate putting values through your model and recording the outputs.
A very simple approach begins with putting your list of inputs in column E as in your example picture. Note down the start and end row numbers - 2 and 5 in your example (as your input values are in the range E2:E5).
In the VBA editor created a new sub in a new module to hold your code (you can Google how to do this). The code is fairly simple.
Sub TurnInputsIntoOutputs()
' First we create some useful and important variables
Dim inputStartRow As Long ' The row your input values start on
Dim inputEndRow As Long ' The row your input values end on
Dim currentRow As Long ' A placeholder for when we cycle through the rows
Dim processingWorksheet As Worksheet ' How we're going to reference your worksheet
' Then we put values into those variables
inputStartRow = 2
inputEndRow = 5
Set processingWorksheet = ThisWorkbook.Sheets("*the name of your worksheet here*")
' Now we cycle through the input rows
For currentRow = inputStartRow to inputEndRow
' Put input value from the current row of column E into cell B1
processingWorksheet.Range("B1").Value = processingWorksheet.Range("E" & currentRow).Value
' Put the resulting output value into the current row of column F
processingWorksheet.Range("F" & currentRow).Value = processingWorksheet.Range("B2").Value
Next currentRow
End Sub
And then just run your macro (you can link it to a Form button or just run it from the VBE - easy enough for your to Google how to do).

VBA Excel — Insert symbol based on cell value

I need to work with Excel to which I am absolutely new. I am looking for a VBA solution to speed up some daily work. Here is my case: I need to check cells of Column C which has negative, positive and netural values and then insert sysmbols in corresponding cells of Column B.
For instance, if C4 has a positive value (2,345), B4 should have &u& as symbol. If C5 has negative value (-12.98), then B5 should have &d& as a symbol. And if C6 has a netural value (0.000), then B6 should be inserted with &n& as a symbol.
An empty B column already exists and values are all in Column C.
As Kyle says, all you need for this is a simple (well, nested) if-formula:
=IF(C1<0;"&d&";IF(C1>0;"&u&";"&n&"))
The format is pretty straightforward, the if has three parts separated by semicolons. The first is the logical test, what you test for, in this case if the value in C1 is smaller (or larger) than 0. The next is the value you want in the cell if the the statement in the test is true, and finally what to put in if it is false.
In this case, we test again if C1 is not smaller than 0, to see if it is larger than zero, that is why there is another if-statement inside the first one.
To apply the formula to your entire column, just copy it down the entire way, and the cell it refers to should update automatically.
Give this a try:
Sub WhatEver()
Dim C As Range
Set C = Intersect(ActiveSheet.UsedRange, Range("C:C"))
For Each cc In C
ccv = cc.Value
If ccv <> "" Then
If ccv = 0 Then
cc.Offset(0, -1).Value = "&n&"
ElseIf ccv > 0 Then
cc.Offset(0, -1).Value = "&u&"
Else
cc.Offset(0, -1).Value = "&d&"
End If
End If
Next cc
End Sub

Using Duplicate Detection to enter a 1/0 in a separate column

The conditional formatting options works well to identify duplicates. How could I use the detected duplicates to write a value to a separate column? 1 for duplicate, 0 for not a duplicate. I thought I could use a VBA function based on the cell colour. Excel however does not store the dup detected cell color in the normal cell color property.
Note: 99 is not the light red color number, it's just for reference.
Function LightRed(rng As Range) As Boolean
If rng.Interior.ColorIndex = 99 Then
LightRed = 0
Else
LightRed = 1
End If
End Function
As tigeravatar said, you can use
=--(COUNTIF(A:A,A1)>1)
to detect duplicates and then you can apply a condition formatting on Column B where if cell value = 1, change background color to red

Partial string match translation table

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:

Excel conditional formatting for the entire row with more than one formula

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

Resources