ArrayFormula of Resetting Running Total in Google Sheets - google-sheets

I'm looking for a (non-dragging) ArrayFormula of running total that resets every time the value in alt column changes. example:
desired result
a 2 2
a 3 5
a 5 10
b 2 2
c 3 3
c 4 7
so every time value in the 1st column changes the sum resets. the table is always sorted if it matters.
non-reseting regular running total formulae:
=ARRAYFORMULA(SUMIF(ROW(B1:B6), "<="&ROW(B1:B6), B1:B6))
=ARRAYFORMULA(MMULT(TRANSPOSE((ROW(B1:B6)<=TRANSPOSE(ROW(B1:B6)))*B1:B6), SIGN(B1:B6)))
I was trying somehow to combine it with this counter formula but no luck so far:
=ARRAYFORMULA(COUNTIFS(A1:A6, A1:A6, ROW(A1:A6), "<="&ROW(A1:A6)))
also I did some research, but only found either script which I am not interested in or dragging/MS Excel formulae solutions like:
=SUM(INDIRECT("L"&SUMPRODUCT(MAX(($H$2:H4=0)*ROW($H$2:H4)))+1):L5)
-----------------------------------------------------------------------------------------------------------
=SUM(L$3:L5)-SUM(M$4:M4)
-----------------------------------------------------------------------------------------------------------
=SUM($C$2:$C2)-IFERROR(SUM($C$2:OFFSET($C$1,LOOKUP(2,1/($B$2:$B2="reset"),ROW($B$2:$B2)-ROW($B$2)+1),0)),0)
-----------------------------------------------------------------------------------------------------------
=MOD((ROW()-ROW(E$1))*1,(1+5))

modification of #JPV solution focused on speed:
=INDEX(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))
shortened:
=INDEX(LAMBDA(x, MMULT(1*TRANSPOSE(IF((TRANSPOSE(ROW(x))>=
ROW(x))*(x=TRANSPOSE(x)), OFFSET(x,,1), 0)), ROW(x)^0))
(A2:INDEX(A:A, MAX(ROW(A:A)*(A:A<>"")))))
=INDEX(IF(B2:B="",, ROW(B2:B) - VLOOKUP(ROW(B2:B), FILTER(ROW(B2:B), B2:B<>"", B2:B<>B2:Boffset1), 1, 1) + 1)) - B=T/F.txt

In addition, you could also try
=ArrayFormula(if(len(A:A),mmult(--transpose(if( (transpose(row(A:A))>=row(A:A))*(A:A=transpose(A:A)),B:B, 0)),row(A:A)^0),))
This should also work if the data is unsorted.

If the table is always sorted on column A, you can just do:
=ARRAYFORMULA(SUMIF(ROW(B1:B6), "<="&ROW(B1:B6), B1:B6)-SUMIF(A1:A6, "<"&A1:A6, B1:B6))
If the table is not sorted, you can still do it with a vlookup:
=ARRAYFORMULA(SUMIF(ROW(B1:B6), "<="&ROW(B1:B6), B1:B6)-SUMIF(row(A1:A6), "<"&vlookup(A1:A6,{A1:A6,row(A1:A6)},2,false), B1:B6))

Related

Google Sheet - It's possible to array sum function in the following condition?

Would it be possible to use arrayformular for this condition?
Sum all the rows that PID are the same, the result should be as in the image.
I tried this code, but I think it's too long, and if the PID exceed over 20 rows, it would not work.
=IF(A3<>A2,BJ3+IF(A3=A4,BJ4,0)+IF(A3=A5,BJ5,0)+IF(A3=A6,BJ6,0)+IF(A3=A7,BJ7,0)+IF(A3=A8,BJ8,0)+IF(A3=A9,BJ9,0)+IF(A3=A10,BJ10,0)+IF(A3=A11,BJ11,0)+IF(A3=A12,BJ12,0)+IF(A3=A13,BJ13,0)+IF(A3=A14,BJ14,0)+IF(A3=A15,BJ15,0)+IF(A3=A16,BJ16,0)+IF(A3=A17,BJ17,0)+IF(A3=A18,BJ18,0)+IF(A3=A19,BJ19,0)+IF(A3=A20,BJ20,0)+IF(A3=A21,BJ21,0)+IF(A3=A22,BJ22,0),0)
With a table like this :
ID
Value
1
5
1
10
2
5
2
10
2
15
You have an expected output of :
ID
Value
Sum
1
5
15
1
10
blank
2
5
30
2
10
blank
2
15
blank
It is achievable with this formula (just drag it in your sum column) :
=IF(A2=A1,"",SUMIFS(B$2:B$12,A$2:A$12,A2))
It check if the ids are the same and then sum them, but only show them on the row where the id first appears
Found it on google by searching google sheets sum group by
The following in C2 will generate the required answer without any copying-down required:
=arrayformula(if(len(A2:A),ifna(vlookup(row(A2:A),query({row(A2:B),A2:B},"select min(Col1),sum(Col3) where Col2 is not null group by Col2"),2,false)),))
We are making a lookup table of grouped sums against the first row of each 'P#' group using QUERY, then using VLOOKUP to distribute the group sums to the first row in each group. Probably also doable using a SCAN/OFFSET combination as well, I think.

Using ARRAYFORMULA to Calculate Running Total of Payables (Alternative to INDIRECT)

I use a Google Spreadsheet to keep track of the accounts payable per vendor. There is a sheet per vendor in the Spreadsheet. A simplified sheet looks like this:
When I receive a new invoice, an entry for the amount is made in the Credit column and when I release a payment, an entry for the amount is made in the Debit column. I keep track of the running total in the AC Payable column. I achieve this by using a formula in each cell of the AC Payable column (the example below is from cell E4):
=IF(
ISNUMBER(INDIRECT(ADDRESS(ROW()-1,COLUMN()))),
INDIRECT(ADDRESS(ROW()-1,COLUMN()))+C4-D4,
C4-D4
)
The logic is simple. The running total for row n is calculated by:
AC Payable(n - 1) + Credit(n) - Debit(n)
This setup works fine, except I have to drag the formula into newly added rows. Is there a way to achieve this by using ARRAYFORMULA?
PS: I have found a solution using:
= ARRAYFORMULA(
SUMIF(
ROW(C3:C),
"<="&ROW(C3:C),
C3:C)
-
SUMIF(
ROW(D3:D),
"<="&ROW(D3:D),
D3:D
)
)
I feel this is a suboptimal (The original sheet dates back to 2018. It has a lot of rows) solution since, in every row, it calculates the total of the Debit and Credit columns up to the current row and then subtracts the total of the Debit column from the total of the Credit column.
I am expecting a solution that would take advantage of the running total available in the previous row and not redo the whole calculation per row.
solution for up to 1581 rows:
=ARRAYFORMULA(QUERY(QUERY(MMULT(TRANSPOSE((SEQUENCE(COUNTA(A3:A)*2)<=
SEQUENCE(1, COUNTA(A3:A)*2))*FLATTEN(INDIRECT("C3:D"&COUNTA(A3:A)+ROW(A3)-1)*{1, -1})),
SEQUENCE(COUNTA(A3:A)*2, 1, 1, 0)), "offset 1", ), "skipping 2", ))
skills:
it's fast
it's smart
gets slower more rows you add
dies after 1581 rows
it's based on standard MMULT Running/Cumulative Total/Sum formula:
=ARRAYFORMULA(MMULT(TRANSPOSE((ROW(B1:B6)
<=TRANSPOSE(ROW(B1:B6)))*B1:B6), SIGN(B1:B6)))
but with a modification twist, because you got 2 columns to total
instead of ROW(B1:B6) we use a sequence of count of real data multiplied by two (because you got 2 columns):
SEQUENCE(COUNTA(A3:A)*2)
instead of TRANSPOSE(ROW(B1:B6)) we use again:
SEQUENCE(1, COUNTA(A3:A)*2)
combination of these pieces:
=ARRAYFORMULA(TRANSPOSE((SEQUENCE(COUNTA(A3:A)*2)<=SEQUENCE(1, COUNTA(A3:A)*2))))
will produce a matrix like:
and that's the reason why it dies with lots of rows because while you may think that if you have only 1500 rows in two columns, then formula will work only on 1500*2=3000 virtual cells, but in fact the MMULT formula processes (1500*2)*(1500*2)=9000000 virtual cells. still, it's worth to note, that this MMULT fx is great if deployed on a small scale.
next, instead of *B1:B6 we use:
*FLATTEN(INDIRECT("C3:D"&COUNTA(A3:A)+ROW(A3)-1)*{1, -1}))
eg. with INDIRECT we take only "valid" range of C3:D which is in your example sheet just C3:D5 and we multiply C column by 1 and D column by -1 to simulate subtraction and then we FLATTEN both columns into one single column. the part +ROW(A3)-1 is just an offset because you start from row 3
and the last part of standard RT fx - SIGN(B1:B6) is replaced with one column full of ones:
SEQUENCE(COUNTA(A3:A)*2, 1, 1, 0)
then we offset the output with inner QUERY by 1 because we are interested in a totals after subtraction and finally we use skipping 2 which means that we filter out every second value - again, we are interested in totals after subtraction of D column.
solution for more than 1581 rows:
=ARRAYFORMULA(
SUMIF(SEQUENCE(COUNTA(A3:A)), "<="&SEQUENCE(COUNTA(A3:A)), INDIRECT("C3:C"&COUNTA(A3:A)))-
SUMIF(SEQUENCE(COUNTA(A3:A)), "<="&SEQUENCE(COUNTA(A3:A)), INDIRECT("D3:D"&COUNTA(A3:A))))
skills:
supports more rows
looks less smart
sadly the third argument of SUMIF always needs to be a range
gets slower with more rows
it will get sick if you feed it with 10000 rows
it may kill off your sheet with 11000+ rows
Here'a modification of Ben Collins' running total formula
=ARRAYFORMULA(
IF(ISBLANK(A2:A),,
MMULT(TRANSPOSE((ROW(C2:C)<=TRANSPOSE(ROW(C2:C)))*C2:C),SIGN(C2:C))-
MMULT(TRANSPOSE((ROW(D2:D)<=TRANSPOSE(ROW(D2:D)))*D2:D),SIGN(D2:D))))
yet another alternative to MMULT:
=INDEX(QUERY(FLATTEN(QUERY(QUERY(TRANSPOSE(QUERY(QUERY(TRANSPOSE(
(SEQUENCE(COUNTA(A3:A)*2)<=SEQUENCE(1, COUNTA(A3:A)*2))*
FLATTEN(INDIRECT("C3:D"&COUNTA(A3:A)+ROW(A3)-1)*{1, -1})),
"offset 1", ), "skipping 2", )), "select "&QUERY(
"sum(Col"&SEQUENCE(COUNTA(A3:A))&"),",, 9^9)&"' '"),
"offset 1", )), "where Col1 is not null", ))
but again, LTE (<=) limitation of 10M cells won't let you use more than 1581 rows in your case or 3162 rows in the standard cumulative sum case
(1581 rows * 2 columns) raised on 2nd power < 10 million cells
(1581*2)^2 = 9998244

Running SUM with ARRAYFORMULA

I have a list of values per day and I want, for each day, to sum the last 7 days using an array formula.
Basically, I want to use this formula
=SUM(A1:A7) inside an ARRAYFORMULA but I can't get it to work.
Theoretically it should look something like
ARRAYFORMULA(SUM(B1:B:B7:B)) which of course doesn't work.
Note: the formula must be at the top row, since new data is added daily so row 2 of today will become row 3 tomorrow. The solution therefor must fit the top cell of the column.
I created a sheet with an example. Col A is dates, Col B is values Col C is the manual sum of the 7 days just as a reference
https://docs.google.com/spreadsheets/d/1jsC5mN2Bdq5a1u2GjoufTTPmSjyurOPd1YXQEv_AGfk/edit#gid=0
I have entered the following in cell D2:
=flatten(
index(
query(
if(
(sequence(counta(B2:B))<sequence(1,counta(B2:B))+7)*
(sequence(counta(B2:B))>=sequence(1,counta(B2:B))),
B2:B,
),
"select sum(Col"&join("), sum(Col",sequence(counta(B2:B)))&")"),
2))
You can also use this old-school method:
=ArrayFormula(if(isnumber(B:B),sumif(row(B:B),"<"&row(B:B)+7,B:B)-sumif(row(B:B),"<"&row(B:B),B:B),))
Or better this to include a header:
=ArrayFormula(if(B:B="",,if(isnumber(B:B),sumif(row(B:B),"<"&row(B:B)+7,B:B)-sumif(row(B:B),"<"&row(B:B),B:B),"Running Total")))

Total Sum With Vlookup

I have two spreadsheets with names and times. One is specific session times and on the second sheet, I want to sum up the total times based on each instance from sheet one.
Sheet 1: Session Time
Name | Time
David 5
Mike 2
Daniel 3
David 2
Daniel 8
Sheet 2: Total Time (The one for which I need a forumula)
Name | Total Time
David 7
Mike 2
Daniel 11
I tried a countif and vlookup but I couldn't get it match more than one instance of the name on sheet 1. I also tried this suggested formual from a suggested post but its not summing a second instance of the user name
=ARRAYFORMULA(SUM(ifna(VLOOKUP(A2, 'Sheet 1'!A3:AA16, 5, false))))
A2 = David (On Sheet 2)
Sheet 1'!A3:AA16 = List of names in columns A and all the way to AA is a series of columns with numerical values
5 = the column number from with I want to return the sum for every instance of David (2 in this example with a total of 7)
False = its not sorted
Any help is mucho appriciado!
You can use this formula in your Sheet2!B1:
={"Total Time";arrayformula(if(A2:A<>"",sumif(Sheet1!A1:A,A2:A,Sheet1!B1:B),""))}
Or simply use =arrayformula(if(A2:A<>"",sumif(Sheet1!A1:A,A2:A,Sheet1!B1:B),"")) in Sheet2!B2
Get the sum of the range based on a specific criteria using SUMIF()
Basically, get the sum of Sheet1!B1:B if Sheet1!A1:A matches the current cell being checked in arrayformula A2:A
Output:
This can be accomplished with a simple QUERY, e.g.,
=QUERY('Session Time'!A:B, "Select A, SUM(B) WHERE A Is Not Null GROUP BY A LABEL SUM(B) 'Total Time'")

Autofill numbers based on column

This may seem extremely elementary, however, I haven't been able to figure it out. I am wanting to be able to autofill a number series up to 6.
For example, the column would go from 1, 2, 3, 4, 5, 6 down each row, and then start over after 6. The columns in A2 would have the item and the columns in f are the position of the item in the gallery (crm requires 6 for each). Basically, it would repeat itself based on column A2. Is there a formula or an array type formula for this or something like it?
try:
=ARRAYFORMULA(IF(A2:A="",,FLATTEN(SPLIT(QUERY(REPT(" "&
QUERY(SEQUENCE(6, 1),,9^9), ROUNDUP(COUNTA(A2:A)/6)),,9^9), " "))))
You can use this formula in cell F2.
=ARRAYFORMULA(MOD(ROW(A2:A)-2,6)+1)
This would get the row number from A2, subtract by 2, divide by 6 and get the remainder, then add by 1.
Here is a row-agnostic version based on Carlos M's suggestion:
=ArrayFormula(IF(A2:A="",,MOD(SEQUENCE(ROWS(A:A)-ROW(),1,0),6)+1))
By "row agnostic," I mean that if the parallel range were moved to be A3:A or A5:A, etc., that is the only part of the formula that would need to be adjusted; the rest would accommodate without change.

Resources