I am having trouble with arrayformula.
I have some data at Col A & B, SUMIF($A$2:$A2,"ABC",$B$2:$B2) works perfectly fine, but I'd like to use arrayformula so I don't have to drag down the formula.
But using ArrayFormula(SUMIF($A$2:$A2,$C$1,$B$2:$B2)) doesn't do anything at all, is there any way I can make it work? I have no idea how.
Here is another option (say, in E2):
=ArrayFormula(IF(A2:A="",,SUMIF(ROW(A2:A)*IF(A2:A="ABC",1,9^9),"<="&ROW(A2:A),B2:B)))
How It Works:
IF(A2:A="",, means "If a row in A2:A is blank, do nothing for that row."
ROW(A2:A)*IF(A2:A="ABC",1,9^9) will create a number based on the row number at each row: the row number itself multiplied by 1 for rows matching "ABC" (resulting in the row number again, since anything times 1 is itself) or multiplied by 9^9 (i.e., some enormous number, which will be the result of for all rows that are not "ABC").
This will be matched against the condition "<="&ROW(A2:A). So only rows at or before "each row" that matched "ABC" will deliver results.
try in E2:
=INDEX(IF(A2:A="ABC",MMULT(1*TRANSPOSE(IF((TRANSPOSE(ROW(
INDIRECT("A2:A"&MAX(ROW(A2:A)*(A2:A<>"")))))>=ROW(
INDIRECT("A2:A"&MAX(ROW(A2:A)*(A2:A<>"")))))*(
INDIRECT("A2:A"&MAX(ROW(A2:A)*(A2:A<>"")))=TRANSPOSE(
INDIRECT("A2:A"&MAX(ROW(A2:A)*(A2:A<>""))))),
INDIRECT("B2:B"&MAX(ROW(A2:A)*(A2:A<>""))), 0)), ROW(
INDIRECT("A2:A"&MAX(ROW(A2:A)*(A2:A<>""))))^0),))
Related
I'm trying to understand this auto-increment formula, that my colleague has written. I understand how arrayformula usually works and also countifs.
Formula from the screen: =ARRAYFORMULA(COUNTIFS(ROW(B2:B), "<="&ROW(B2:B)))
I'm stacked about why ROW(B2:B) (1param in COUNTIFS) as a range works fine. It should be a range, not just a number that ROW function returns.
I have been trying to find an answer, read documentation, but nothing helped.
I think that, for example, for 4th line the formula would look like this (if we seperate from ARRAYFORMULA):
COUNTIFS(ROW(B4:B), "<="&ROW(B4:B)),
COUNTIFS(4, "<=4")
I need to understand this code, not other solutions.
The best way to understand how an ARRAYFORMULA works is to write down the equivalent drag-down formula.
The equivalent drag-down formula for:
=ARRAYFORMULA(COUNTIFS(B2:B, B2:B, ROW(B2:B), "<="&ROW(B2:B)))
is
=ARRAYFORMULA(COUNTIFS($B$2:$B, B2, ROW($B$2:$B), "<="&ROW(B2)))
=ARRAYFORMULA(COUNTIFS($B$2:$B, B3, ROW($B$2:$B), "<="&ROW(B3)))
=ARRAYFORMULA(COUNTIFS($B$2:$B, B4, ROW($B$2:$B), "<="&ROW(B4)))
...
(We only need ARRAYFORMULA because ROW($B$2:$B) is an array formula, which means that if you type it in a cell without wrapping it an an array-enabling function it will only evaluate ROW($B$2))
If we recall the COUNTIFS parameters:
=COUNTIFS(criteria_range1, criterion1, criteria_range2, criterion2)
We can see that in the drag-down formula, every parameter that by default expects a range, becomes an absolute reference and every parameter that by default does not expect a range, is just a single value that increments each row.
This is true for any other function: if a function has a parameter that by default expects a range, when we wrap it in ARRAYFORMULA(), that range stays the same throughout the entire computation, which means that every single value in that range is seen by the array formula at any time. What increments, and therefore is only seen by the array formula on that specific row, are the parameters that do not natively expect a range.
This seems like an obvious observation but I'm sure it's the reason many people are confused about how that formula works.
If you understand this concept, then you can also understand how the other variants of the formula work:
=ARRAYFORMULA(COUNTIFS(B2:B, B2:B, ROW(B2:B), "<"&ROW(B2:B)))
=ARRAYFORMULA(COUNTIFS(B2:B, B2:B, ROW(B2:B), ">="&ROW(B2:B)))
=ARRAYFORMULA(COUNTIFS(B2:B, B2:B, ROW(B2:B), ">"&ROW(B2:B)))
every next row is by logic an incrementation of the previous row +1. what this formula does it checks the given row number against row number. for example, for row 4, COUNTIFS checks if ROW(A4) is smaller or equal to ROW(A4). then the evaluation is "yes, row 4 is equal to row 4" and the output is TRUE. what COUNTIF actually does is counting these TRUE outputs up to every row summing all the previous rows. something like:
rows
COUNTIFS processing
output
counting TRUEs
final output
row 1
row 1 equal to row 1?
TRUE
1st TRUE
1
row 2
row 2 equal to row 2?
TRUE
2nd TRUE
2
row 3
row 3 equal to row 3?
TRUE
3rd TRUE
3
row 4
row 4 equal to row 4?
TRUE
4th TRUE
4
row 5
etc
etc
etc
etc
I am having difficulties trying to get an array formula to increment a column and restart the increment whenever a condition has been met.
Here is an example of what I am trying to achieve, but this has been done manually. It would be great if this could work in an array formula as we'll be adding more rows and would rather not drag the formula down.
[Update based on feedback of the original post]
Column A contains a list of names and teams.
Names are already organised into teams.
The aim is to go through each row and provide a name with an index starting from 1.
Then when a new team is found in column A the index starts again from 0.
The aim is to make this an Array Formula to avoid having to manually re-add the formula when more rows are added.
Link to sheet:
https://docs.google.com/spreadsheets/d/1K00LRFNrN99fFXQO1tzp8jjZeCuTxwENXNGuLj0K0ao/edit?usp=sharing
Example
Any thoughts or advice on this would be greatly appreciated.
I've added a new sheet ("Erik Help") to your sample spreadsheet. It contains the following formula in B1:
=ArrayFormula({"ID Index"; IF(A2:A="",, IF( REGEXMATCH(LOWER(A2:A),"team"), 0, ROW(A2:A) - VLOOKUP(ROW(A2:A), FILTER(ROW(A2:A), REGEXMATCH(LOWER(A2:A),"team")), 1, TRUE)))})
The header text is included in the formula. You can change it as you like.
If a cell in A2:A is blank, the corresponding cell in B2:B will be as well.
If REGEXMATCH finds a match with "team" in the lowercase rendering of a cell in A2:A, 0 will be returned for the corresponding cell in B2:B.
Otherwise, VLOOKUP will lookup each remaining row number in a FILTERed array containing only those row numbers where the word "team" appears. (In your sample set, that will be 2, 8, 12). When the exact match is not found (which it will not be for any remaining row), TRUE tells VLOOKUP that, since the search array is in strict ascending order, we want it to "bump back" to the most recent value found. In each case, the returned row number of the most recent row containg "team" is then subtracted from the actual row number to produce the recurring incremental numbering 1, 2, 3, etc.
try:
=INDEX(IFNA(1*IF(REGEXMATCH(A2:A, "Day"), 0, REGEXEXTRACT(A2:A, "(\d+)"))))
I wanted a ArrayFormula at C1 which gives the required result as shown.
Entry sheet:
(Column C is my required column)
Date Entered is the date when the Name is Assigned a group i.e. a, b, c, d, e, f
Criteria:
The value of count is purely on basis of Date Entered (if john is assigned a on lowest date(10-Jun) then count value is 1, if rose is assigned a on 2nd lowest date(17-Jun) then count value is 2).
The value of count does not change even when the data is sorted in any manner because Date Entered column values is always permanent & does not change.
New entry date could be any date not necessarily highest date (If a new entry with name Rydu is assigned a on 9-Jun then the it's count value will become 1, then john's (10-Jun) will become 2 and so on)
Example:
After I sort the data in any random order say like this:
Random ordered sheet:
(Count value remains permanent)
And when I do New entries in between (Row 4th & 14th) and after last row (Row 17th):
Random Ordered sheet:
(Doesn't matter where I do)
I already got a ArrayFormula which gives the required result:
={"AF Formula1"; ArrayFormula(IF(B2:B="", "", COUNTIFS(B$2:B, "="&B2:B, D$2:D, <"&D2:D)+1))}
I'm not looking for another Arrayformula as solutions. What I want is to know what is wrong in my ArrayFormula? and how do I correct it?
I tried to figure my own ArrayFormula but it's not working:
I got Formula for each cell:
=RANK($D2,FILTER($D$2:$D, $B$2:$B=$B2),1)
I figured out Filter doesn't work with ArrayFormula so I had to take a different approach.
I took help from my previous question answer (Arrayformula at H3) which was similar since in both cases each cell FILTER formula returns more than 1 value. (It was actually answered by player0)
Using the same technique I came up with this Formula which works absolutely fine :
=RANK($D2, ARRAYFORMULA(TRANSPOSE(SPLIT(VLOOKUP($B2, SUBSTITUTE(TRIM(SPLIT(FLATTEN(QUERY(QUERY({$B:$B&"×", $D:$D}, "SELECT MAX(Col2) WHERE Col2 IS NOT NULL GROUP BY Col2 PIVOT Col1", 1),, 9^9)), "×")), " ", ","), 2, 0), ","))), 1)
Now when I tried converting it to ArrayFormula:
($D2 to $D2:$D & $B2 to $B2:$B)
=ARRAYFORMULA(RANK($D2:$D,TRANSPOSE(SPLIT(VLOOKUP($B2:$B, SUBSTITUTE(TRIM(SPLIT(FLATTEN(QUERY(QUERY({$B:$B&"×", $D:$D}, "SELECT MAX(Col2) WHERE Col2 IS NOT NULL GROUP BY Col2 PIVOT Col1", 1),, 9^9)), "×")), " ", ","), 2, 0), ",")), 1))
It gives me an error "Did not find value '' in VLOOKUP evaluation", I figured out that the problem is only in VLOOKUP when I change $B2 to $B2:$B.
I'm sure VLOOKUP works with ArrayFormula, I fail to understand where my formula is going wrong! Please help me correct my ArrayFormula.
Here is the editable sheet link
if I understand correctly, you are trying to "rank" B column based on D column dates in such way that dates are in theoretical ascending order so if you randomize your dataset, the "rank" of each entry would stay same and not change based on the randomness you introduce.
therefore the correct formula would be:
={"fx"; INDEX(IFNA(VLOOKUP(B2:B&D2:D,
{INDEX(SORT({B2:B&D2:D, D2:D}, 2, 1),,1),
IFERROR(1/(1/COUNTIFS(
INDEX(SORT(B2:D, 3, 1),,1),
INDEX(SORT(B2:D, 3, 1),,1), ROW(B2:B), "<="&ROW(B2:B))))}, 2, 0)))}
{"fx"; ...} array of 2 tables (header & actual table) under each other eg. ;
outer shorter INDEX or longer ARRAYFORMULA (doesnt matter which one) is needed coz we are processing an array
IFNA for removing possible #N/A errors from VLOOKUP function when VLOOKUP fails to find a match
we VLOOKUP joint B and D column B2:B&D2:D in our virtual table {} and returning second 2 column if there is an exact match 0
our virtual table {INDEX(SORT({B2:B&D2:D, D2:D}, 2, 1),,1), ...} we VLOOKUP from is constructed with 2 columns next to each other eg. ,
we are getting the first column by creating an array of 2 columns {B2:B&D2:D, D2:D} next to each other where we SORT this array by date/2nd column 2, in ascending order 1 but all we need after sorting is the 1st column so we use INDEX where we bring all rows ,, and the first column 1
now lets take a look on how we getting the 2nd column of our virtual table by using COUNTIFS which will mimic the "rank"
IFERROR(1/(1/ is used to remove all zero values from the output (all empty rows would have 0 in it as the "rank")
under COUNTIFS we put 2 pairs of arguments: "if column is qual to column" and "if row is larger or equal to next row increment it by 1" ROW(B2:B), "<="&ROW(B2:B))
for "if column is qual to column" we do this twice and use range B2:D and sort it by date/3rd column 3 in ascending order 1 and of this we again need only the 1st column so we INDEX it and return all rows ,, and first column 1
with this formula you can add, remove or randomize your dataset and you will always get the right value for each of your rows
as for why your formula doesnt work... to not get #N/A error for vlookup you would need to define the end row of the range but still, the result wont be as you would expect coz formula is not the right one for this job.
as mentioned there are functions that are not supported under AF like SUM,AND,OR and then there are also functions which work but in a different way like IFS or with some limitations like SPLIT,GOOGLEFINANCE,etc.
I have answered you on the tab in your shared sheet called My Practice thusly:
You cannot split a two column array as you have attempted to do in cell CI2. That is why your formula does not work. You can only split a ONE column array.
I understand you are trying to learn, but attempting to use complicated formulas like that is going to make it harder I'm afraid.
So I have this formula that copies rows (with data in col A) into a new range. Column A contains number indicating how many duplicates the row should yield in the result. Also the output rows gets sorted based on the value in column A.
=sort(arrayformula(vlookup(
transpose(split(query(rept(row(D2:D)&" ",A2:A),,9^9)," ")),
arrayformula({row(D2:D),{A2:A,D2:F}}),
{2,3,4,5},
0)),
1,
TRUE)
This is not exectly what I need thou. Instead of having a single value in the cells in column A that indicates how many times the row should be duplicated I need to have a text string like “2,3,5” in every cell in that column, where the individual numbers in the string indicates the position of the row in output (rather than the number of times the row should be copied).
For example, in the output I want the row with the string “2,3,5” to be copied three times. The output should have one of the rows be 2:nd from top, the other 3:rd from top, and the last one the 5:th from top.
If I could have the A2:A part of this range {A2:A,J2:N} instead contain the matching values for split(A2:A) I think it would do what I want.
This is a copy of my google sheet. Hopefully it's possible to understand what it is I'm trying to achieve.
https://docs.google.com/spreadsheets/d/1sp5DRBwFP0-aG-FvjUPKBmyylz0WoPB63ASOOdUGdnI/edit?usp=sharing
I've got the following Google spreadsheet:
item have ready need1 need2 need3
A 1 2 1
B 1 2 1 1
C 2 2
etc
I want to fill ready column as follows:
find the first column in need1, ..., needN range which has a non-empty value
if the value found is less or equals the value in have column, set ready column to something cheerful (e.g. yes)
if the value found is larger than the value in have column, don't do anything
So above input, when processed should look like this:
item have ready need1 need2 need3
A 1 2 1
B 1 2 1 1
C 2 yes 2
For the first step I found a suggested solution, which did not work for me:
=INDEX( SORT( FILTER( D10:H10 , LEN( D10:H10 ) ) ,
FILTER( COLUMN( D10:H10 ) , LEN( D10:H10 ) ) , 0 ) , 1 )
(it returns #REF!) Not sure what's wrong with it or how to proceed to the next step.
Thanks in advance!
If you know how many need columns you have, or even just how many columns are on the sheet, this is quite straightforward. If not and you need to look at the entire row, you might have to redesign a bit to avoid a circular reference from the cell with the formula being part of that row.
Your second two steps are fairly simple either way - you want one of two results based on a condition, so you're going to want to use =IF. Your condition is that the 'need' number is less than or equal to the 'have' number, and you want it to say 'yes' if that's true, and nothing if it isn't. So, that gives us:
=IF(need<=have, "Yes", "")
The examples below assume your table above starts from cell A1 in the top left, and that the last column in your sheet is Z
Next we need to find 'need' and 'have'. Finding 'have' is pretty easy - it's just the number in column B.
Finding 'need' is slightly more complicated. You've got the right idea using INDEX and FILTER, but your formula seems a little overcomplicated. Basically we can use FILTER to filter out the blank values, and INDEX to find the first one that is left. First, FILTER:
The range you want to filter from is everything in the same row from column D to column Z (or whatever the final column is), and the condition you want to filter for is that those same cells are not blank. For the formula you're typing into cell C2, that gives us:
=FILTER(D2:Z2, D2:Z2<>"")
Next, INDEX: If you give INDEX an array, a row number, and a column number, it will tell you what is at that the cell where that row and column meet. As we've filtered out the blanks, we just want whatever is left in the first column of our filtered array, which gives us:
=INDEX(FILTER(D2:Z2, D2:Z2<>""), 1, 1)
Or, as we only have one row in our array, and INDEX is pretty smart, simply:
=INDEX(FILTER(D2:Z2, D2:Z2<>""), 1)
So to bring it all together, our final formula for cell C2 is:
=IF(INDEX(FILTER(D2:Z2, D2:Z2<>""), 1)<=B2, "Yes", "")
Then just drag the formula down for as many rows as you need. If your sheet is or becomes wider, just change Z to whatever your last column is.
When you don't know the size of a range, use functions row, column, rows, columns.
Simple formula
Here's an example of what you are looking:
=if(INDEX(FILTER(OFFSET(D2,,,1,COLUMNS(1:1)-column(D2)+1),OFFSET(D2,,,1,COLUMNS(1:1)-column(D2)+1)<>""),1)<=B2,"yes","")
this part of formula:
OFFSET(D2,,,1,COLUMNS(1:1)-column(D2)+1)
returns the range starting from given cell (D2) to the end of Sheet (COLUMNS(1:1)-column(D2)+1)
ArrayFormula
I suggest using ArrayFormula, it'll expand automatically:
=ARRAYFORMULA(if(REGEXEXTRACT(SUBSTITUTE(trim(transpose(query(transpose(OFFSET(D2,,,COUNTA(A2:A),COLUMNS(1:1)-column(D2)+1)),,COLUMNS(OFFSET(D2,,,COUNTA(A2:A),COLUMNS(1:1)-column(D2)+1)))))," ",", "),"\d+")*1<=OFFSET(B2,,,COUNTA(A2:A)),"yes",""))
It assumes that 'Item' column has no blank values.
The solution from #Max Makhrov works, and has the advantage of using a single formula for the whole column.
However, it assumes that all of your columns at the right from your ready column (D) will be need_ columns.
The solution from #dmusgrave also works, provided you remove the extra "=" before INDEX:
=IF(INDEX(FILTER(D2:Z2,D2:Z2<>""),1)<=B2,"Yes","").
However, it makes the same assumption, and also limits at column Z.
Such assumptions seem reasonable, but if they are limiting you, here's how you can have any number of need_ columns starting right of your ready column:
=IF(INDEX(FILTER(INDIRECT( "D"&ROW()&":"&CHAR(67+COLUMNS(FILTER($1:$1,LEFT($1:$1, 4)="need")))&row() ), INDIRECT( "D"&ROW()&":"&CHAR(67+COLUMNS(FILTER($1:$1,LEFT($1:$1,4)="need")))&row() )<>""),1)<=B2,"Yes","")
The idea is simply to replace D2:Z2 (in #dmusgrave's solution) by :
INDIRECT( "D"&ROW()&":"&CHAR(67+COLUMNS(FILTER($1:$1,LEFT($1:$1, 4)="need")))&row() )
Explanation: You start from D at current row, and you go until the last need_ column on the same current row.
CHAR(68) is D, to which you add the number of columns titled need.*, minus one (hence the 67).
Using the same logic, you can easily make your formula more robust/generic, such as not having the need_ columns starting right form the ready column, etc.