I have the following formula in W407 and it returns 3.33333333333333E-06.
=LOOKUP(2,1/INDEX(SUBTOTAL(2,OFFSET($A5,ROW($A5:$A400)-ROW($A5),0))*W5:W400,0))
The "SUBTOTAL(2,...)" function returns an array with a bunch of 0 and 1, 0 for invisible cells and 1 for visible cells. In this particular case, only A182 to A199 are visible. So, it returns an array with 396 elements, in which element 177 to 194 has a value of 1, the rest 0.
In W5:W400, only W199 (element 194) has a value of 300,000, the rest 0.
The INDEX function multiplies these two arrays element by element, giving an array with 396 elements. Since in the second array, only element 194 is not 0, the resulting array is a 0 array except element 194, which is 300,000.
Now, why does LOOKUP returns 3.33333333333333E-06?
So your formula is =LOOKUP(2,1/300000)
1/300,000 is 3.33333E-06 and, from the Office docs:
If the LOOKUP function can't find the lookup_value, the function matches the largest value in lookup_vector that is less than or equal to lookup_value.
3.33333E-06 is 0.00000333333, which is definitely smaller than 2. As it's the only element in the array which is no-zero, that's what is returned.
Related
I want to consolidate the data of column B into a single cell ONLY IF the index (ie., Column A) is duplicated.
For example:
Currently, I'm doing manually for each duplicated index by using the following formula:
=TEXTJOIN(", ",TRUE,B4:B6)
Is there a better way to do this all at once?
Any help is appreciated.
There may easier way but you can try this formula-
=BYROW(A2:A17,LAMBDA(p,IF(INDEX(MAP(A2:A17,LAMBDA(x,SUM(--(A2:INDEX(A2:A17,ROW(x)-1)=x)))),ROW(p)-1,1)=1,TEXTJOIN(", ",1,FILTER(B2:B17,A2:A17=p)),"")))
Using REDUCE might be possible for a more succinct solution, though try this for now:
=BYROW(A2:A17,LAMBDA(ζ,LET(α,A2:A17,IF((COUNTIF(α,ζ)>1)*(COUNTIF(INDEX(α,1):ζ,ζ)=1),TEXTJOIN(", ",,FILTER(B2:B17,α=ζ)),""))))
For the sake of alternatives about how to solve it:
Using XMATCH/UNIQUE
=LET(A, A2:A17, ux, UNIQUE(A),idx, FILTER(XMATCH(ux, A), COUNTIF(A, ux)>1),
MAP(SEQUENCE(ROWS(A)), LAMBDA(s, IF(ISNA(XMATCH(s, idx)), "", TEXTJOIN(",",,
FILTER(B2:B17, A=INDEX(A,s)))))))
or using SMALL/INDEX to identify the first element of the repetition:
=LET(A, A2:A17, n, ROWS(A), s, SEQUENCE(n),
MAP(A, s, LAMBDA(aa,ss, LET(f, FILTER(B2:B17, A=aa), IF((ROWS(f)>1)
* (INDEX(s, SMALL(IF(A=aa, s, n+1),1))=ss), TEXTJOIN(",",, f), "")))))
Here is the output:
Explanation
XMATCH and UNIQUE
The main idea here is to identify the first unique elements of column A via ux, and find their corresponding index position in A via XMATCH(ux, A). It is an array of the same size as ux. Then COUNTIF(A, ux)>1) returns an array of the same size as XMATCH output indicating where we have a repetition.
Here is the intermediate result:
XMATCH(ux, A) COUNTIF(A, ux)>1)
1 FALSE
2 FALSE
3 TRUE
6 FALSE
7 TRUE
9 TRUE
11 FALSE
12 TRUE
15 FALSE
16 FALSE
so FILTER takes only the rows form the first column where the second column is TRUE, i.e the index position (idx) where the repetition starts. For our sample it will be: {3;7;9;12}.
Now we iterate over the sequence of index positions (s) via MAP . If s is found in idx via XMATCH (also XLOOKUP(s, idx, TRUE, FALSE) can be used for the same purpose) then we join the values of column B filtered by column A equal to INDEX(A,s).
SMALL and INDEX
This is a more flexible approach because in the case we want to do the concatenation in another position of the repetition you just need to specify the order and the formula doesn't change.
We iterate via MAP through elements of column A and index position (s). The name f has the filtered values from column B where column A is equal to a given value of the iteration aa. We need to identify only filtered rows with repetition, so the first condition ROWS(f) > 1 ensures it.
The second condition identifies only the first element of the repetition:
INDEX(s, SMALL(IF(A=aa, s, n+1),1))=ss
The second argument of SMALL indicates we want the first smallest value, but it could be the second, third, etc.
Where A is equal to aa, IF assigns the corresponding value of the sequence (remember IF works as an array formula), if not then it assigns a value that will never be the smallest one, for example, n+1, where n represents the number of rows of column B. SMALL returns the smallest index position. If the current index position ss is not the smallest one, the conditions FALSE.
Finally, we do a TEXTJOIN only when both conditions are met (we multiply them to ensure an AND condition).
I am trying to obtain the location of the maximum value in an excel spreadsheet (see below).
Date Tommy Jamie Clara
01/2013 1.51% -6.96% 0.38%
02/2013 1.75% -6.96% -0.49%
03/2013 2.22% -6.96% 0.59%
04/2013 1.90% -5.48% -1.16%
05/2013 2.03% -5.48% 0.23%
06/2013 1.90% -5.48% -0.47%
07/2013 2.51% -0.90% -0.65%
08/2013 3.06% -0.90% 1.54%
The problem in this case however is that both the row and column numbers are not known. So far I have tried the following:
=CELL("address",INDEX($B$1:$D$9, MATCH(MAX($B$1:$D$9),$B$1:$D$9,0),3))
but realized that the MATCH function will only accept a single column, hence the second argument of the MATCH function herein produces an error. Likewise, the third argument of the INDEX function (written as "3") would be wrong as well - since I do not know what column the maximum value of the array would lie.
I tried various stuff but to no avail. Would be glad to get any assistance in this regard.
You can use INDEX/AGGREGATE:
=CELL("address";INDEX($A$1:$D$9; AGGREGATE(14;6;(ROW($B$2:$D$9)/(MAX($B$2:$D$9)=$B$2:$D$9));1);AGGREGATE(14;6;(COLUMN($B$2:$D$9)/(MAX($B$2:$D$9)=$B$2:$D$9));1)))
Explanation:
I assume that you are familiar with the CELL and INDEX functions, so I will only explain the AGGREGATE part.
AGGREGATE(14,6,(ROW($B$2:$D$9)/(MAX($B$2:$D$9)=$B$2:$D$9)),1)
The first argument (14) indicates that the LARGE subfunction will be used.
The second argument (6) indicates that errors will be ignored.
The third argument creates an array of row number values.
The fourth argument (1) states that the first largest value should be returned.
I will show you how an array of row numbers is created in steps:
ROW(B2:D9) returns an array with all row numbers in the range:
2,2,2;
3,3,3;
4,4,4;
...
9,9,9
MAX($B$2:$D$9)=$B$2:$D$9 returns a bool array:
FALSE, FALSE, FALSE;
FALSE, FALSE, FALSE;
FALSE, FALSE, FALSE;
...
TRUE, FALSE, FALSE
Dividing by each other, bool values are converted to FALSE = 0, TRUE = 1, resulting in an array:
#DIV/0!, #DIV/0!, #DIV/0!;
#DIV/0!, #DIV/0!, #DIV/0!;
#DIV/0!, #DIV/0!, #DIV/0!;
...
9, #DIV/0!, #DIV/0!
Errors are ignored and as a result we get 9
The column is calculated analogously.
If there are several identical MAX values in the range, then this formula will not work - you can use the following array formula instead:
=ADDRESS(INT(MIN(IF($B$2:$D$9=MAX($B$2:$D$9),ROW($B$2:$D$9)*1000+COLUMN($B$2:$D$9)))/1000),MOD(MIN(IF($B$2:$D$9=MAX($B$2:$D$9),ROW($B$2:$D$9)*1000+COLUMN($B$2:$D$9))),1000),4)
It will return address of the first MAX value.
Array formula after editing is confirmed by pressing ctrl + shift + enter
I am using excel's aggregate (small) function to find the smallest value for each name that appears in a column. The issue is that the formula below simply returns 0s everywhere there is a value in B.
The formula I am using is
=IF($B2<>"", AGGREGATE(15,7, ($B:$B)*($A2=$A:$A)*($B2<>""), 1), "")
where B contains the data I want the smallest value from and A contains identifying strings.
I appreciate any help you can lend!
You want to divide by the criteria:
=IF($B2<>"", AGGREGATE(15,7, ($B:$B)/(($A2=$A:$A)*($B:$B<>"")), 1), "")
Whenever ($A2=$A:$A) or ($B2<>"") is FALSE it will return 0 and anything multiplied by 0 is 0 and as such the smallest value is 0.
By dividing by the criteria we throw an #DIV/0 error which the 7 in the AGGREGATE's second criterion forces the formula to ignore and as such we only get the smallest of what returns TRUE or 1 in both Boolean. 1*1=1.
But one more thing. AGGREGATE is an array type formula so limiting the to only the data will speed it up.
=IF($B2<>"", AGGREGATE(15,7, ($B$1:INDEX($B:$B,MATCH("zzz",$A:$A)))/(($A2=$A$1:INDEX($A:$A,MATCH("zzz",$A:$A)))*($B$1:INDEX($B:$B,MATCH("zzz",$A:$A))<>"")), 1), "")
As per your comment:
=IF($B2 = AGGREGATE(15,7, ($B:$B)/(($A2=$A:$A)*($B:$B<>"")), 1),AGGREGATE(15,7, ($B:$B)/(($A2=$A:$A)*($B:$B<>"")), 1), "")
I am attempting to write an equation that compares a date to an array of other dates given the same ID and then returns the minimum value found between 0 and 42 or returns a zero if the criteria does not match.
My current equation can identify whether a date pair matches the above criteria and returns a 1 if there is a match and a 0 for no match.
=IF(E15<>"",IFERROR(--(AGGREGATE(15,7,(E15-$H$2:$H$8000)/(($C$1:$C$8000=C15)*(E15-$H$2:$H$8000>=0)),1)<43),0),0)
I need to modify this equation to return the actual difference between the dates rather than just a 1 or 0.
I have been playing around with an equation like this:
=IF(E3<>"", IFERROR(IF(--(AGGREGATE(15, 6, (E3-$H$2:$H$8000)/(--($C$2:$C$8000=C3)*--(E3-$H$2:$H$8000>=0)), 1)<43)=1, MIN(--($C$2:$C$8000=C3)*(E3-$H$2:$H$8000)), ""), 0), 0)
But it returns nothing but zeros.
Please find sample data and expected values below.
For what you want you only need to move the check for less than 43 into the Aggregate and return blanks instead of 0:
=IF(E15<>"",IFERROR(AGGREGATE(15,7,(E15-$H$2:$H$8000)/(($C$1:$C$8000=C15)*(E15-$H$2:$H$8000>=0)*(E15-$H$2:$H$8000<43)),1),""),"")
I have this excel formula that someone has created without documentation and I'm struggling to understand it.
=SUMPRODUCT(-MID(TEXT(MID(TEXT(F2,REPT(0,15)),ROW(INDIRECT("1:15")),1)*{2;1;2;1;2;1;2;1;2;1;2;1;2;1;2},"00"),{1,2},1))
it looks like it creates a "random" digit from another number.
There are few key things I'm stuggling with:
* why is there an array ({1,2}) given to a MID() function?
* since there is a SUMPRODUCT(), which needs an array, I'm assuming that the result of the -MID() function is some sort of an array, how do I see what it is?
* what does multplying by an array {2;1;2;1;2;1;2;1;2;1;2;1;2;1;2} does?
* the INDIRECT() functions seems to always return 1?
any help would be appriciated.
There is a function in EXCEL called Evaluate Formula, a good tool to check the formula step by step.
Assuming F2 is 123
REPT(0,15)
Generate a string with 15 "0", that is "000000000000000"
TEXT(F2,[1])
Convert F2 into a string with 15 char. Eg. 123 > "000000000000123"
ROW(INDIRECT("1:15"))
Return an array {1;2;3;4;5;6;7;8;9;10;11;12;13;14;15}
MID([2],[3],1)
Separate [2] into an array, each element is a char {"0";"0";"0";"0";"0";"0";"0";"0";"0";"0";"0";"0";"1";"2";"3"}
[4]*{2;1;2;1;2;1;2;1;2;1;2;1;2;1;2}
Since {A;B} * {C;D} = {A*C;B*D}
{"0";"0";"0";"0";"0";"0";"0";"0";"0";"0";"0";"0";"1";"2";"3"}*{2;1;2;1;2;1;2;1;2;1;2;1;2;1;2}
={0*2;0*1;0*2;....}={0;0;0;0;0;0;0;0;0;0;0;0;2;2;6}
TEXT([5],"00")
Converts the elements in the Array to two char by adding "0" in the front. The array goes to {"00";"00";"00";"00";"00";"00";"00";"00";"00";"00";"00";"00";"02";"02";"06"}
MID([6],{1,2},1)
Note that {A,B} and {A;B} are different. {A,B} is an array with 1 row and 2 columns; {A;B} is an array with 2 rows and 1 column.
In this formula, you can imagine doing MID twice, first time we use 1 as second parameter, second time we use 2 instead.
The result is a 2-D array:
{"0","0";"0","0";"0","0";"0","0";"0","0";"0","0";"0","0";"0","0";"0","0";"0","0";"0","0";"0","0";"0","2";"0","2";"0","6"}
SUMPRODUCT(-[7])
The minus sign before [7] will force all elements in the array to convert to numbers with opposite sign.
In this example, it sums 0+0+0+...+(-2)+0+(-2)+0+(-6) = -10