ArrayFormula with GoogleFinance dynamic date - google-sheets

First of all, i'm not a powerful sheets user :)
I'm trying to use GOOGLEFINANCE to calculate amounts in multiple currencies.
I use this formula:
=IF($A2;
IF(
$C2:C;
$C2:C;
IF(
$D2:D;
$D2:D*INDEX(GoogleFinance("CURRENCY:USDUAH";"close";$A2);2;2);
$E2:E*INDEX(GoogleFinance("CURRENCY:EURUAH";"close";$A2);2;2)
));
0)
A-column contains dates,
C,D,E - amounts in 3 different currencies.
IFs are just to prioritize columns :)
The formula works well but i need to "extend" it each time i add row - to increment
$A2 -> $A3 to get rate for specified date.
I try to use ArrayFormula but it turns out it keeps reference to $A2 so i get same rate irrelevant from date specified in A-cells.
I have created sample sheet to illustrate:
https://docs.google.com/spreadsheets/d/1K2TbGIWl7JacYKiWgwwmJfelxJ-7fa9F9obp5XswW18/edit?usp=sharing
I have allowed editing by anyone, so if you decide to edit - please don't remove anything :) also you can drop your username in sticky row(above your proposed solution)
Is there a way to apply ArrayFormula to this to make it work?
Maybe you can provide more readable solution to nested IFs.

try:
=ARRAYFORMULA(IF(A2:A<>"";
IF(C2:C<>""; C2:C;
IF(D2:D<>""; VLOOKUP(TO_TEXT(A2:A);
TO_TEXT(QUERY(GOOGLEFINANCE("CURRENCY:USDUAH";
"close"; MIN(A:A); MAX(A:A)+1);
"offset 1 format Col1'dd.mm.yy'"; 0)); 2; 0)*1;
VLOOKUP(TO_TEXT(A2:A);
TO_TEXT(QUERY(GOOGLEFINANCE("CURRENCY:EURUAH";
"close"; MIN(A:A); MAX(A:A)+1);
"offset 1 format Col1'dd.mm.yy'"; 0)); 2; 0)*1)); ))

There is a new simpler and more flexible method now since the introduction of LAMBDA and its helper functions in Google Sheets in August 2022.
Assuming dates in A2:A, and amounts in UAH, USD, EUR in C2:C, D2:D, E2:E respectively, then the following formula will work, e.g. in cell F2:
=MAP(A2:A;C2:C;D2:D;E2:E;
LAMBDA(date;uah;usd;eur;
IFS(
uah;uah;
usd;usd*INDEX(GOOGLEFINANCE("currency:usduah";"price";date);2;2);
eur;eur*INDEX(GOOGLEFINANCE("currency:euruah";"price";date);2;2);
ISBLANK(date);)))
The trick here is that MAP(LAMBDA) calculates the specified formula for each row of the input array separately (effect similar to manually expanding the formula over the whole range), whereas ARRAYFORMULA passes the whole array as an argument to the formula (GOOGLEFINANCE is special and doesn't work intuitively with such input).
This general method with MAP(LAMBDA) can now be used to pass any arguments to GOOGLEFINANCE in a way one would otherwise expect to do with ARRAYFORMULA.

Try This One:
=arrayformula(
IF(query(arrayformula(if(A2:A="",False,True)),
"Select * where Col1=True"),
IF( $C2:C,
$C2:C,
IF( $D2:D,
$D2:D*INDEX(GoogleFinance("CURRENCY:USDUAH","close",$A2),2,2),
$E2:E*INDEX(GoogleFinance("CURRENCY:EURUAH","close",$A2),2,2))),0))

Related

Inconsistent results when using arrayformula within Googlesheets

I have a formula that will calculate the working hours between two dates.
It works perfectly well when referring a few lines and ranges. As the data in this sheet is going to be automatically added to over time I wanted to use arrayformula to automatically calculate the duration for these new rows.
However when used within arrayforumla the values are unpredictably different.
I can't make any sense of why it's different.
Below is an example;
https://docs.google.com/spreadsheets/d/1cWZwpnkp2MPyM-EppjOYHRcMEcblscU70R62uf691Xw/edit#gid=0
Any suggestions as to why the formula is behaving differently would be greatly appreciated!
Edit
For posterity;
Formula that worked when inline (COL C);
=TEXT((NETWORKDAYS.INTL(A2,B2,1,F$7:F$9)-1)*($G$2-$F$2)+IF(NETWORKDAYS.INTL(B2,B2,1,F$7:F$9),MEDIAN(MOD(B2,1),$F$2,$G$2),$G$2)-MEDIAN(NETWORKDAYS.INTL(A2,A2,1,F$7:F$9)*MOD(A2,1),$F$2,$G$2),"[hh]:mm:ss")
Forumla that didn't work in arrayformula (COL D);
=ARRAYFORMULA(
IF(ROW(B:B)=1, "Array Formula Duration",
IF(ISBLANK(B:B),"",
(NETWORKDAYS.INTL(A2:A,B2:B,1,F$7:F$9)-1)*($G$2-$F$2)+IF(NETWORKDAYS.INTL(B2:B,B2:B,1,F$7:F$9),MEDIAN(MOD(B2:B,1),$F$2,$G$2),$G$2)-MEDIAN(NETWORKDAYS.INTL(A2:A,A2:A,1,F$7:F$9)*MOD(A2:A,1),$F$2,$G$2)
)
)
)
Forumla that sorted it (COL E);
={"Array Formula Duration";map(A2:A,B2:B,lambda(a,b,if(b="",,TEXT((NETWORKDAYS.INTL(a,b,1,F7:F9)-1)*(G2-F2)+IF(NETWORKDAYS.INTL(b,b,1,F7:F9),MEDIAN(MOD(b,1),F2,G2),G2)-MEDIAN(NETWORKDAYS.INTL(a,a,1,F7:F9)*MOD(a,1),F2,G2),"[hh]:mm:ss"))))}
You may try:
={"Array Formula Duration";map(A2:A,B2:B,lambda(a,b,if(b="",,TEXT((NETWORKDAYS.INTL(a,b,1,F7:F9)-1)*(G2-F2)+IF(NETWORKDAYS.INTL(b,b,1,F7:F9),MEDIAN(MOD(b,1),F2,G2),G2)-MEDIAN(NETWORKDAYS.INTL(a,a,1,F7:F9)*MOD(a,1),F2,G2),"[hh]:mm:ss"))))}

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")))

Formula that will skip one column when calculating SUM() or similar functions

I'd like to run a =SUM(A1:G1), but always skip one column, regardless if it has value or not.
In this case, it should calculate A1+C1+E1+G1.
Is there another function I could append to SUM() or other similar functions as SUM in order to skip one column?
Thank you!
Using the following method you can calculate any number of alternate columns, without the need of manual +
Suppose your data is in second row onwards, use this formula
=SUMPRODUCT(A2:G2, MOD(COLUMN(A2:G2),2))
Simply a sumproduct of cell values and a array of {1,0,1,0,1...}
Another slight variation
=SUMPRODUCT(A2:G2*ISODD(COLUMN(A2:G2)))
But if the even columns contain letters instead of numbers this will give an error, so you can use instead
=SUMPRODUCT(N(+A1:G1)*ISODD(COLUMN(A1:G1)))
Comparing #AnilGoyal's answer, this works as well
=SUMPRODUCT(A1:G1,--ISODD(COLUMN(A1:G1)))
You can use:
=SUM(INDEX(A1:G1,N(IF(1,{1,3,5,7}))))
Or with Excel O365:
=SUM(INDEX(A1:G1,{1,3,5,7}))
A bit more of a general solution:
=SUMPRODUCT(MOD(COLUMN(A1:G1),2)*A1:G1)
Or with Excel O365:
=SUM(MOD(COLUMN(A1:G1),2)*A1:G1)
Or even:
=SUM(INDEX(1:1,SEQUENCE(4,,1,2)))
Since you included Google-Sheets, I'll throw in an option using QUERY():
=SUM(QUERY(TRANSPOSE(1:1),"Select * skipping 2"))
Maybe a bit more verbose, but very understandable IMO.
Consider something of the format:
=SUM(A1:G1)-INDEX(A1:G1,2)
The 2 in the formula means remove the 2nd item in the part of the row. (so the 999 is dropped)
So the formula =SUM(BZ10:ZZ10)-INDEX(BZ10:ZZ10,2) drops CA10 from the sum, etc.(a similar formula can be constructed for columns)
google sheets:
=INDEX(MMULT(N(A1:H3), 1*ISODD(SEQUENCE(COLUMNS(A:H)))))
=INDEX(IF(ISODD(COLUMN(A:H)), TRANSPOSE(MMULT(TRANSPOSE(
IFERROR(A1:H3*ISODD(COLUMN(A:H)), 0)), 1^ROW(A1:A3))), ))

Google Spreadsheet Function That Sums Numbers In A Column When the Row Contains An EXACT Text

I've been at this problem for a while now. I am trying to sum numbers under a specific column when the rows equal a certain text and then display that sum on a different sheet. So far I came up with this formula: =IF(EXACT(A2,Table!A2:A)=TRUE,SUM(Table!C2:C)); however the only problem is that is sums everything in column C (which makes sense).
I wish there was a way to do something like the following: SUM(Table!C2:C where EXACT(A2,TABLE!A2:A)=TRUE). I've also tried the SUMIF(), DSUM(), and QUERY() functions to no avail. I must be getting logically tripped up somewhere.
Figured it out: =SUM(FILTER(Table!E4:E, EXACT(Table!A4:A,A4)=TRUE)).
=sum ( FILTER (b1:b10, a1:a10 = "Text" ) )
// the above formula will help you to take the sum of the values in column B when another column A contain a specific text.
The formula is applicable only in Google Spreadsheets

arrayformula sum in Google spreadsheet

How do you arrayformula() a sum() such as:
=sum(A1:H1)
I need to go down 1000 rows.
Another option:
=ArrayFormula(SUMIF(IF(COLUMN(A1:H1),ROW(A1:A1000)),ROW(A1:A1000),A1:H1000))
Of the two answers that work, Jacob Jan Tuinstra and AdamL, Jacob gives a better answer. Jacob's runs faster and is easier to remember.
However, why use crazy formulas when it is much easier to use Google Sheets to the fullest?
=ARRAYFORMULA(A2:A+B2:B+C2:C+D2:D+E2:E+F2:F+G2:G+H2:H)
In the foregoing formula, you can use named ranges instead of the ranges by reference.
=ARRAYFORMULA(range1+range2+range3+range4+range5+range6+range7+range8)
As well, you can sum across rows that span sheets rather than being stuck working with columns within the same sheet.
To fix the formula to block returning zeros for blank rows, use this:
=arrayFormula(if(isNumber(A2:A),A2:A+B2:B+C2:C+D2:D+E2:E+F2:F,G2:G,H2:H))
See: See Ahab's answer on Google Forums
For a cool sum accumulation formula, see Otávio Alves Ribeiro's answer on Google Forums
This is what you are looking for:
=MMULT(A1:H1000,TRANSPOSE(ARRAYFORMULA(COLUMN(A1:H1000)^0)))
See this answer on Web Application I gave: https://webapps.stackexchange.com/a/53419/29140
Note: tried it on the new Google Spreadsheet, without succes.
with new functions in google sheets (since 20 Sep, 2022) all you need is:
=BYROW(A:H; LAMBDA(x; SUM(x)))
Summing A-H horizontal and running down for 523 lines:
=ARRAYFORMULA(iferror(mmult(A1:H523;TRANSPOSE(column(A1:H1))^0)))
if I look at this formula I really think the following might be simpler. Add this to Tools > Script Editor:
function row_sum(range_to_sum_per_row) {
var result_column = [];
for (var r = 0; r < range_to_sum_per_row.length; r++) {
var row_sum = parseFloat(0);
for (var c = 0; c < range_to_sum_per_row[r].length; c++) {
row_sum += range_to_sum_per_row[r][c] || 0;
}
result_column.push([row_sum]);
}
return result_column;
}
use this like so for performance reasons, where C:H is the range you want to sum up and A:A is a column that does not contain an empty string:
=row_sum(filter(C2:H, len(A2:A)>0))
If you want to be able to add rows and sum to the last row for all values in A1:H, you can use:
=ArrayFormula(SUMIF(IF(COLUMN(A1:H1),ROW(A1:A)),ROW(A1:A),A1:H))
Alternatively, if you want be be able to add rows and columns to the spreadsheet and sum to the last of both this can also be done. Paste the following code into any cell and it will create a column of summed values for all cells in each row below and to the right of pasted cell:
=arrayformula(SUMIF(IF(COLUMN(indirect(concatenate(REGEXREPLACE(address(row(),column()+1),"[^[:alpha:]]", ""),VALUE(REGEXREPLACE(address(row(),column()),"[^[:digit:]]", "")),":",VALUE(REGEXREPLACE(address(row(),column()),"[^[:digit:]]", ""))))),ROW(indirect(concatenate(REGEXREPLACE(address(row(),column()+1),"[^[:alpha:]]", ""),VALUE(REGEXREPLACE(address(row(),column()),"[^[:digit:]]", "")),":",REGEXREPLACE(address(row(),column()+1),"[^[:alpha:]]", ""))))),ROW(indirect(concatenate(REGEXREPLACE(address(row(),column()+1),"[^[:alpha:]]", ""),VALUE(REGEXREPLACE(address(row(),column()),"[^[:digit:]]", "")),":",REGEXREPLACE(address(row(),column()+1),"[^[:alpha:]]", "")))),indirect(concatenate(concatenate(REGEXREPLACE(address(row(),column()+1),"[^[:alpha:]]", ""),VALUE(REGEXREPLACE(address(row(),column()),"[^[:digit:]]", "")),":"),address(rows($A:$A),columns($1:$1))))))
Using Query
=INDEX(TRANSPOSE(
QUERY(TRANSPOSE(FILTER(A2:H,A2:A<>"")),
"select sum(Col"&JOIN("), sum(Col",SEQUENCE(COUNTA(A2:A)))&")",0)
),,2)
notes:
generating query string on the fly
Using DSUM:
=ARRAYFORMULA(DSUM(
TRANSPOSE(FILTER({A2:A,A2:H},A2:A<>"")),
SEQUENCE(COUNTA(A2:A)),{IFERROR(1/0);IFERROR(1/0)}))
notes:
{IFERROR(1/0);IFERROR(1/0)} is to make zero creteria for DSUM.
{A2:A,A2:H} -- added fake column for DSUM to mimic header column.
may be able to cahnge the formula into DMAX or DAVERAGE
Answer similar to #adamL suggestion, but removing the internal if.
=ArrayFormula(
sumif(ROW(A1:A10)*COLUMN(A1:H1)^0,ROW(A1:A10),A1:A10)
)
In this case I use ROW(A1:A10) * COLUMN(A1:H1)^0 to generate the row number matriz. To understand how it works, you can test just this part in your Google sheets:
= ArrayFormula(ROW(A1:A10) * COLUMN(A1:H1)^0)
So, with your row matrix, sumif can operate for each line, is the line has the matched row number, it will be summed up.
Let us not complicate this.
Simply put parenthesis in each of the array in the range.
=arrayformula( Sum( (A1:A):(H1:H) )
This spans not only upto 1000 rows but upto infiinity.
If you really want to limit then go
=arrayformula( Sum( (A1:A1000):(H1:H1000) )

Resources