2D vector lookup [x;y] - excel

I've got a matrix, with two coordinates [i;j]
I'm trying to automatize a lookup:
As an example, this would have the coordinates of [1;2]
Here's a table of all the coordinates:
So here, obviously [1;2] would equate to 143,33
To simplify the issue:
I'll try to go step by step over what I'm trying to do to make the question bit less confusing.
Think of what I'm trying to do as a function, lookup(i, j) => value
Now, refer to the second picture (table)
I find all rows containing index [i] (inside column C) and then
only for those rows find row containing index [j] (inside column D ∩ for rows from previous step)
Return [i;j] value
So if u invoked lookup(2, 4)
Find all rows matching i = 2
Row 5: i = 2 ; j = 3
Row 6: i = 2 ; j = 4
Row 7: i = 2 ; j = 5
Lookup column j for j=4 from found rows
Found row 6: i = 2 ; j = 4.
Return value (offset for yij column = 143,33)
Now this isn't an issue algorhitmically speaking, but I have no idea how to go about doing this with excel formulas.
PS: I know this is reltively simple vba issue but I would prefer formulas
PSS: I removed what I tried to make the question more readable.

You can use SUMPRODUCT, which return 0 for not found values:
=SUMPRODUCT(($C$4:$C$18=$I4)*($D$4:$D$18=J$3)*$E$4:$E$18)
or AGGREGATE, which returns an error that can be hidden by the IFERROR function:
=IFERROR(AGGREGATE(15,6,(1/(($C$4:$C$18=$I12)*($D$4:$D$18=J$3)))*$E$4:$E$18,1),"")

You can use SUMIFS here assuming you will not have exact duplicate combinations of [i, j]. If you did have a duplicate combination, the amounts will be summed and placed in the corresponding cell
In cell B2 place this equation: =SUMIFS($Q$2:$Q$16,$P$2:$P$16,B$1,$O$2:$O$16,$A2) and drag across and over as needed
IF you want to convert the 0's to blanks you can nest the above formula inside a text formatter like so:
=TEXT([formula], "0;-0;;#")

Related

How to color max. 2 consecutive values in Excel without using VBA?

I'm out of idea how I could format consecutive same (respectively only even) values in Excel tables without using VBA.
The conditional formatting shall color only consecutive values and only
all 0s or all even values, when there are not more than 2.
A: ID
B: binary
C: counting
1
1
1
2
0
2
3
0
2
4
1
3
5
0
4
6
0
4
7
0
4
8
1
5
9
1
5
I tried to format with: =COUNTIF(C1:C9, C1) < 3, but then it also colors the 1s and C6:C7, eventho there are more than 2.
I also tried =AND( COUNTIF(C1:C9,C1) < 3, ISEVEN(C1:C9) ) but then it colors nothing.
I could replace the 0s with empty cells so I could check ISEMPTY(B1:B9) but it again colors nothing. Using $ to set absolute changes nothing as well.
Formating duplicates also colors triplets, which also doesn't work for me.
=OR(COUNTIF($C$1:$C$9,C1) = 1, COUNTIF($C$1:$C$6,C1) = 2) works so far, but also colors the 1s (uneven).
=AND(OR(COUNTIF($C$1:$C$9,C1) = 1, COUNTIF($C$1:$C$6,C1) = 2), ISEVEN($C$1:$C$9)) doesn't work.
=AND(OR(COUNTIF($C$1:$C$9,C1) = 1, COUNTIF($C$1:$C$6,C1) = 2), $B$1:$B$9 <> 1) doesn't work as well.
My only solution so far is using 2 formating rules:
color =OR(COUNTIF($C$1:$C$9,C1) = 1, COUNTIF($C$1:$C$6,C1) = 2)
do not color =$B$1:$B$9 = 1
but I think it is terrible.
I worked on it for some hours, maybe I'm missing something really obvious.
I'm not allowed to use VBA, therefore this is ot an option.
EDIT: My 2.rule-solution can be simplificed with:
color =COUNTIF($C$1:$C$9,C1) < 3
do not color =$B$1:$B$9 = 1
I'm still confused why combining both doesn't work:
AND(COUNTIF($C$1:$C$9,C1) < 3; $B$1:$B$9 <> 1)
EDIT2: I know why it didn't work. Don't check <>1 with absolute value-range $B$1$:$B$9
Solution: B1 <> 1 then it loops through.
Now combining both works:
=AND( COUNTIF($C$1:$C$9, C1) < 3, B1 <> 1)
I can't see an easy answer for the binary numbers. You have two cases:
(1) Current cell is zero, previous cell is 1, next cell is zero and next cell but one is 1.
(2) Current cell is zero, previous cell is zero, previous cell but one is 1, next cell is 1.
But then the first pair of numbers is a special case because there is no previous cell.
Strictly speaking the last pair of numbers is a special case as well because there is no following cell.
=OR(AND(ROW()=1,B$1=0,B$2=0,B$3=1),AND(ROW()=2,B$1=0,B$2=0,B$3=1),AND(B1=0,B1048576=1,B2=0,B3=1),AND(B1=0,B1048576=0,B1048575=1,B2=1))
where I have used the fact that you are allowed to wrap ranges to the end of the sheet (B1048576) in conditional formatting.
Adding the condition for the case where there there are two zeroes at the end of the range:
=OR(AND(ROW()=1,B$1=0,B$2=0,B$3=1),
AND(ROW()=2,B$1=0,B$2=0,B$3=1),
AND(B1=0,B1048576=1,B2=0,OR(B3=1,B3="")),
AND(B1=0,B1048576=0,B1048575=1,OR(B2=1,B2="")))
Even this could go wrong if there was something in the very last couple of rows of the sheet, so I suppose to be absolutely safe:
=OR(AND(ROW()=1,B$1=0,B$2=0,B$3=1),
AND(ROW()=2,B$1=0,B$2=0,B$3=1),
AND(Row()>1,B1=0,B1048576=1,B2=0,OR(B3=1,B3="")),
AND(Row()>2,B1=0,B1048576=0,B1048575=1,OR(B2=1,B2="")))
Shorter:
=OR(AND(ROW()<=2,B$1+B$2=0,B$3=1),
AND(B1+B2=0,B1048576=1,OR(B3=1,B3="")),
AND(B1+B1048576=0,B1048575=1,OR(B2=1,B2="")))
Not the cleanest wat but it works. You only need to move your data 1 row below, so headers would be in row 2 and data in row 3 for this formula to work:
=IF(AND(B3=B4,B3<>B5),IF(AND(B4=B3,B4<>B2),TRUE,FALSE),IF(AND(B3=B2,B3<>B1),IF(AND(B3=B4,B3<>B5),FALSE,TRUE),FALSE))
How about this approach (Office 365):
=LET(range,B$1:B$9,
s,IFERROR(TRANSPOSE(INDEX(range,ROW()+SEQUENCE(5,,-2))),1),
t,TEXTJOIN("",,(s=INDEX(range,ROW()))*ISEVEN(s)),
IFERROR(SEARCH("0110",t)<4,IFERROR(SEARCH("010",t)=2,FALSE)))
It creates an array s of 5 values starting point is the current row of the range, adding the 2 values above and below. If the value is out of range it will replace the error with a 1.
The array s is checked for being even (TRUE/FALSE, IFERROR created values are uneven) and the values to equal the value of the current row of the range (TRUE/FALSE).
These two booleans are multiplied creating 1 for both values being TRUE, else 0.
These values are joined and checked for 2 consecutive 1's (surrounded by 0) to be found in the 2nd or 3rd position of the range (this would be the case if two even consecutive equal numbers are found),
if it errors it will look if a unique even number is found (1 surrounded by 0 in 2nd position).
PS I'm unable to test if conditional formatting allows you to type the range as B:B instead of B$1:B$9 (working from a mobile) but that would make it more dynamical, because that way you can easily expand the conditional range.

VBA function for Upside/Downside Capture

apologies for my ignorance, I'm brand new to VBA - I'm sure this is a simple problem...
I'm trying to write a fn. for up/down side capture in VBA. This is the problem:
There are two columns. One has fund performance in % (I've labelled 'returns'). The other has index performance in % (labelled 'index'). Both are same length / same number of rows. I need both to be variables to enter to the fn.
For UpsideCapture fn., for all nos. in the index column >0, I want to find the corresponding number in the returns column (which will be on the same row). Once I have those numbers I can compound them.
I've tried using Offset, assuming the returns column is 15 columns to the left of the index column but it doesn't return anything, and I don't really want to rely on it always being 15 columns apart (it arbitrary).
Many thanks!
One of my rubbish attempts is below. Any help is much appreciated. Its really just a case of finding the correct corresponding row based on the value in the index column...
Function UpsideCapture(returns As Range, index As Range) As Variant
Dim n As Integer
Dim m As Integer
Dim i As Integer
n = returns.Rows.Count
m = index.Rows.Count
For i = 1 To m
If index(i) > 0 Then
Upsidecap = ((1 + Upsidecap) * (1 + Offset(returns(i), -15))) - 1
End If
Next
UpsideCapture = Upsidecap
End Function
example

Deleting duplicate data in one of three column in Excel

I tried to use some functions that I found whilst searching to solve my problem, they are slightly modified it to remove duplicate data in a field.
File
Rather than a count of 4, I would like the count of 2 from column J. The information below are my attempts for 4 different sections on the attached document as I always thought the next one would give me the result that I wanted.
H ====I==========J
P13C Body Exterior 4943
P13C Body Exterior 4943
P13C Body Exterior 5122
P13C Body Exterior 5122
=IFERROR(INDEX($K$7:$K$142,MATCH(0,COUNTIFS($H$7:$H$142,B14,$K$7:$K$142,$E$14),0)),"")
as does this
=IFERROR(INDEX($J$7:$J$142,MATCH(,IF(H$7:H$142="P13C",COUNTIF(I7:I142,$J$7:$J$142)),)),"")
and this
=IFERROR(INDEX($K$7:$K$142,MATCH(0,COUNTIF($H$7:$H$142,$K$7:$K$142),0)),"")
This, gives me a 0
=IF($J$7:$J$142>1,IF($K$7:$K$142="20",SUM(IF(FREQUENCY($H$7:$H$142,$H$7:$H$142)>1,1))))
This gives me a DIV error
=SUMPRODUCT(((H7:H142="P13C")*(I7:I142="Body Exterior"))/(COUNTIFS(J7:J142, J7:J142, H7:H142, "P13C", I7:I142,"Body Exterior")+((H7:H142<>"P13C")+(I7:I142="Body Exterior"))))
There are duplicates in $J$7:$J$142, but I only want the one count.
Sort the column J in smallest to largest order
concatenate all three values by using '&' on next column K ---> H&I&J
then use IF and COUNTIF formula on next column L,
Column L:
=IF(K1=K2,COUNTIF(K1,K1:K142),"")
this a easy method to get count 1 for J column

how to conditionally match in excel

I've got two data sets: Data-A and Data-B.
Data-A
A B C D Start_Date End_Date
N C P 1 23-05-2015 27-05-2015
N C K 1 30-05-2015 07-06-2015
N C Ke 1 09-06-2015 28-06-2015
N C Ch 1 14-07-2015 25-07-2015
N C Th 1 29-06-2015 13-07-2015
N C Po 2 23-05-2015 27-05-2015
N C Kan 2 30-05-2015 08-06-2015
Data-B
X D Date A B C
444 1 09-07-2015
455 1 20-07-2015
1542 1 28-06-2015
2321 1 21-07-2015
2744 1 01-07-2015
7455 2 25-05-2015
12454 2 02-06-2015
18568 2 24-05-2015
28329 2 03-06-2015
28661 2 31-05-2015
Values is data-Bare missing and I need to fill them using conditional index matching/vlookup such that column D(Data-B) is matched along with Date(Data-B) such that Start Date<= Date <=End Date.
Desired Output:
X D Date A B C
444 1 09-07-2015 N C Th
455 1 20-07-2015 N C Ch
1542 1 28-06-2015 N C Ke
2321 1 21-07-2015 N C Ch
2744 1 01-07-2015 N C Th
7455 2 25-05-2015 N C Po
12454 2 02-06-2015 N C Kan
18568 2 24-05-2015 N C Po
28329 2 03-06-2015 N C Kan
28661 2 31-05-2015 N C Kan
Proof of Concept
In order to achieve the above I used the AGGREGATE function. It is a normal formula that performs array like calculations. The following formula will return the results from the first row that matches your criteria.
=INDEX(A$2:A$8,AGGREGATE(15,6,ROW($D$2:$D$8)/(($J2=$D$2:$D$8)*($E$2:$E$8<=$K2)*($K2<=$F$2:$F$8)),1)-1)
This assumed your table Data-A Started in A1 and included 1 row as a header row. The formula can be place in the first cell under A in Data-B and copied down and to the right as needed.
UPDATE Formula explained
The aggregate function performs array calculations within its brackets for certain sub function. There are about 19 different subfunctions. Subfunction 14 and 15 are both array calculations. This is a nice feature since it does array like calculations while being a regular formula.
Since I wanted the first row that met your criteria, I opted to use the small function or subfunction 15 for the first argument. Basically I am telling the aggregate function to generate a list and sort it in ascending order.
The second argument has a value of 6 which tell the aggregate to ignore any results from the array that generate errors. This will come in very handy if we can make results we do not want turn in to errors.
Now we are getting into the array portion of the formula. You can take this next part of the equation and highlight the appropriate rows in a neighbouring column and enter it as a CONTROL+SHIFT+ENTER (CSE) formula. As long as you do this in the top cell the array formula will propagate to the remainder of the selected cells and show you the results of the array. Also check the formula bar to see if { } appeared around your formula. You cannot add the { } manually.
{=ROW($D$2:$D$8)/(($J2=$D$2:$D$8)*($E$2:$E$8<=$K2)*($K2<=$F$2:$F$8))}
What this will do is determine the current row and then will divide it by the results of our conditions. You can also try each of the following conditions in a separate column as CSE formulas in the same manner described above to see their results.
($J2=$D$2:$D$8)
($E$2:$E$8<=$K2)
($K2<=$F$2:$F$8)
These on their own will provide you with either TRUE or FALSE as it checks each row. Now the interesting thing is, and this applies to excel formulas, when you perform a math operation on a Boolean, it will treat 0 as false and anything other number as TRUE. It will actually convert TRUE to 1. You will also note that each of the logic checks was separated by *. In this case * is acting like an AND operator as only when all results are true will you get an answer of 1. (+ will act like an OR operator)
Now if you remember from earlier 6 said to ignore all errors. So any row that does not meet our logic check will result in a division by 0 since not all logic checks results in TRUE or 1. All the checks that wound up false wind up getting ignored. So now after doing that, a list of only row numbers that met our criteria is left inside the aggregates array.
After the logic check there is a ,1 for the next argument. In this case we are telling the aggregate to return the 1st number in the list which is the first row number that met our criteria. If we wanted the third number, this would be ,3 instead.
So aggregate is returning the first row number of the results we want. When this is paired with an INDEX function, when can use the result to tell us what row of the INDEX function to look in. In this case we said we wanted to look in the index A$2:A$8. The aggregate function is telling us how many rows to go down in the index. If the index had start in row 1 we would not have to do anything. But since there is a header row, we need to adjust the results from the aggregate function by subtracting 1 for the head row (in reality you need to subtract the row number above the start of your data). This is why you see the -1 after the aggregate function.
Now if you pay attention to the lock on the range you will notice I did not lock the A in A$2:A$8. I did this so that I could copy the formula to the right and the column A address would update as I did. This only works because you were keeping the columns in the same order. If the order has changed I would have changed the index from a 1D array to a 2D array and used a MATCH function to line up the column headers.

Excel VBA - Referring between ranges

Here's my problem:
I have two ranges, r_products and r_ptypes which are from two different sheets, but of same length i.e.
Set r_products = Worksheets("Products").Range("A2:A999")
Set r_ptypes = Worksheets("SKUs").Range("B2:B999")
I'm searching for something in r_products and I've to select the value at the same position in r_ptypes. The result of Find method is being stored in cellfound. Now, consider the following data:
Sheet: Products
A B C D
1 Product
2 S1
3 P1
4 P2
5 S2
6 S3
Sheet: SKUs
A B C D
1 SKU
2 S1-RP003
3 P1-BQ900
4 P2-HE300
5 S2-NB280
6 S3-JN934
Now, when I search for S1, cellfound.Row gives me value 2, which is, as I understand, 2nd row in the total worksheet, but is actually 1st row in the range(A2:A999).
When I use this cellfound.Row value to refer to r_ptypes.cells(cellfound.Row), It is taking it as an Index value and returns B3 (P1-BQ900) instead of what I want, i.e. B2 (S1-RP003).
My question is how'll I find out the index number in cellfound? If not possible, how can I use Row number to extract data from r_ptypes?
Dante's solution above works fine. Also, I managed to get the index value using built in excel function Match instead of using Find method of a range. Listing it here for reference.
indexval = Application.WorksheetFunction.Match("searchvalue", r_products, 0)
Using the above, I'm now able to refer the rows in r_ptypes
skuvalue = r_ptypes.Rows(indexval).Value
Because .Row always returns the absolute row number of a sheet, not the offset (i.e. index) in the range.
So, just do some minus job to deal with it.
For you example,
r_ptypes.Cells(cellfound.Row - r_ptypes.Cells(1).Row + 1)
or a little bit neat (?)
With r_ptypes
.Cells(cellfound.Row - .Cells(1).Row + 1)
End With
That is, get the row difference between cellfound and the first cell and + 1 because Excel counts cells from 1.

Resources