Calculate the average of sets of cells satisfying a certain criterion (AVERAGEIF) - google-sheets

This is my Items sheet
And this is my Values sheet
As can be seen from the table, alfa is associated with 20 40 60 80, beta with 30 40 70 80 and gamma with 50 60 70 80.
In the Items sheet in cell B1 (next to the first item) I would like a formula (Arrayformula or alike) generating the average value for each item. In my example it should be:
alfa -> 50 (that is: (20+40+60+80)/4 = 200/4)
beta -> 55 (that is: (30+40+70+80)/4 = 220/4)
gamma-> 65 (that is: (50+60+70+80)/4 = 260/4)
So the final result should be:
This is my googlesheet: example
P.S. For simplicity's sake, I used just columns A:C for items in Values sheet. In real case I have 10 columns so I want to avoid to specify each one in the formula and instead use a range.

try:
=BYROW(A1:A3, LAMBDA(x, INDEX(QUERY(SPLIT(FLATTEN(Values!A1:C10&"​"&Values!D1:D10), "​"),
"select avg(Col2) where Col1 = '"&x&"'"), 2)))
update
=IFERROR(BYROW(A1:INDEX(A:A, MAX(ROW(A:A)*(A:A<>""))),
LAMBDA(x, INDEX(QUERY(SPLIT(FLATTEN(
FILTER(Values!A:C, Values!D:D<>"")&"​"&
FILTER(Values!D:D, Values!D:D<>"")), "​"),
"select avg(Col2) where Col1 = '"&x&"'"), 2))))

Related

Stacking Multiple Arrays In Query/Lambda Function

My question was inspired by this post in that I'm wondering if it's possible to create a formula to stack a dynamic amount of arrays based on a list (see below for clarification).
Sample Starting Data From Three Sources
ID
Amount
India
9
Delta
4
Hotel
8
ID
Amount
Alpha
1
Echo
5
Foxtrot
6
ID
Amount
Bravo
2
Gulf
7
Charlie
3
Desired final result:
ID
Amount
Alpha
1
Bravo
2
Charlie
3
Delta
4
Echo
5
Foxtrot
6
Gulf
7
Hotel
8
India
9
I can get the final result by using a query function as shown in this spreadsheet with a formula referencing the appropriate cells with fileID and range:
=Query({IMPORTRANGE(E2,F2);
IMPORTRANGE(E3,F3);
IMPORTRANGE(E4,F4)},"Select * where Col1 is not null order by Col1",1)
if you want to play with it in your own sheet, you could use this hard-coded function which is the same as above:
=Query({IMPORTRANGE("1WtI56_9mhyArMn_j_H4pZg8E0QdIBaKoJfAr-fDAoE0","'Sheet1'!A:B");
IMPORTRANGE("1HamomAuLtwKJiFEtRKTuEkt--YDTtWChUavetBcAcBA","'Sheet1'!A2:B");
IMPORTRANGE("1WtI56_9mhyArMn_j_H4pZg8E0QdIBaKoJfAr-fDAoE0","'Sheet2'!A2:B")},"Select * where Col1 is not null order by Col1",1)
My Question:
Is there a way to leverage a formula to generate this result based on the number of file ids and ranges in columns E and F? So if a fourth ID and range were added, the desired result in columns a and b would be shown? I suspect Lambda would work, but I am not as strong with it as I should be.
Unsuccessful attempt:
=lambda(someIDs,SomeRanges,IMPORTRANGE(someIds,SomeRanges))(filter(E2:E,E2:E<>""),filter(F2:F,F2:F<>""))
REALLY Bad Attempts:
=contact(Player()*1800-CoffeeBribe*Not(Home))
=company(theMaster(emailed)*(false))<>🐇
All helpful answers will be upvoted if not accepted. Thanks.
if ranges would be the same:
=LAMBDA(x, QUERY(REDUCE({"ID", "Amount"}, x,
LAMBDA(a, c, {a; IMPORTRANGE(c, "Sheet1!A2:B")})),
"where Col1 is not null", 1))
(E2:INDEX(E:E, MAX((E:E<>"")*ROW(E:E))))
if ranges are not the same:
=INDEX(LAMBDA(x, y, QUERY(SPLIT(TRANSPOSE(SPLIT(QUERY(MAP(x, y,
LAMBDA(e, f, QUERY("♣"&FLATTEN(QUERY("♥"&TRANSPOSE(
IMPORTRANGE(e, f)),,9^9)),,9^9))),,9^9),
"♣")), "♥"), "where Col1 <> ' ' order by Col2", 1))(
E2:INDEX(E:E, MAX((E:E<>"")*ROW(E:E))),
F2:INDEX(F:F, MAX((F:F<>"")*ROW(F:F)))))
or:
=LAMBDA(x, QUERY(REDUCE({"ID", "Amount"}, x,
LAMBDA(a, b, {a; IMPORTRANGE(b, OFFSET(b,,1))})),
"where Col2 is not null", 1))
(E2:INDEX(E:E, MAX((E:E<>"")*ROW(E:E))))
in old days it would be solved by generating it:
={""; INDEX("={"&TEXTJOIN("; ", 1, "IMPORTRANGE("""&
FILTER(E2:E, E2:E<>"")&""", """&FILTER(F2:F, F2:F<>"")&""")")&"}")}
REDUCE accepts and returns arrays. We can use it to stack ranges. INDEX/COUNTA can be used to get the range needed without blanks. OFFSET can be used to get the next column's value.
=QUERY(
REDUCE(
{"Id","Amount"},
E2:INDEX(E2:E,COUNTA(E2:E)),
LAMBDA(
a,e,
{a;IMPORTRANGE(e,OFFSET(e,0,1))}
)
),
"Select * where Col1 is not null order by Col1",
1
)

Google Sheets: Perform a running formula in the same column

I have a simple formula I want to perform in the same column.
Link to sheet
Column A: dates
Column C: multiplier
Column B: where I want to perform the formula.
B2 = B1-B1*$C$1
B3 = B2-B2*$C$1 etc
I'd like to automatically run the formula as the number of months (in Col A) changes.
​A
B
C
1/4/22
100
0.5
1/5/22
50
1/6/22
25
try:
=ARRAYFORMULA(IF(A2:A="",,B1*C1^SEQUENCE(COUNTA(A2:A))))
=arrayformula( B1 * (1 - C1) ^ sequence(count(A2:A)) )

How do I create a formula to sum values in one column, but multiply those values by a different column?

I have two Google Sheets. My main sheet keeps track of meetings (total, or "count"), minutes, and meeting categories:
Count Mins Category
1 30 Hiring
5 60 Lunch
3 120 Tasks
1 60 Hiring
2 30 Tasks
...
And here's the sheet I'm trying to figure out:
Categories Count Mins
Hiring 2
Lunch 5
Tasks 5
The "Count" column is correct (I'm using a sumif formula), but I'm not sure how to get the "Mins" column and multiply it by the "Count" column. (To get the total meeting time for the Tasks category I need to add (120 * 3) and (30 * 2).
Is there a way to do that?
use:
=QUERY(QUERY(A1:C,
"select C,sum(A),sum(B)
where A is not null
group by C"),
"offset 1", 0)
then:
=QUERY(QUERY(QUERY(QUERY(A1:C,
"select C,sum(A),sum(B)
where C is not null
group by C"),
"offset 1", 0),
"select Col1,Col2*Col3"),
"offset 1", 0)
After a bit more research I stumbled upon SUMPRODUCT and that turned out to be an easy solution. I'm not familiar with "Query" but it looks super powerful. (Is it similar to SQL?)
Anyway, here is my solution:
=SUMPRODUCT((N6:N1500 = A2),(E6:E1500), (J6:J1500))
If the Category in the N column is a match, multiply the value in the E column by the value in the J column. Easy peasy.

How to change specific values to be a range instead

I have a list of values in Google Sheets for example:
10
14
36
43
64
110
92
103
and I want to change it to a range of
0-20, 21-40, 41-80, 81-120
so that it outputs
2
1
2
3
(two values in the range 0-20, one value in the 21-40 range, two values in the 41-80 range, and three values in the 81-120 range.)
You can do it in one step with the Frequency function FREQUENCY(data, classes):
=frequency(A2:A10,{20,40,80,120})
Note that Frequency creates one count per class, plus an extra count for values which exceed the highest class value. You can suppress this if you want to, but it could be a useful check for outliers.
=QUERY(ARRAYFORMULA({A1:A, IF(LEN(A1:A),
IFERROR(VLOOKUP(A1:A, {{0, "0-20" };
{21, "21-40" };
{41, "41-80" };
{81, "81-120" }}, 2), ),)}),
"select Col2, count(Col2)
where Col2 !=''
group by Col2
label count(Col2)''")
alternatives: https://webapps.stackexchange.com/a/123741/186471

Split 1 column into multiple columns with up to 500 cells each

In Google Sheets, I have a column that is arbitrarily long.
I want to split this column into separate columns of length 500.
How can I do this?
Some things I've been thinking may be involved in a solution:
TRANSPOSE
ARRAY_CONSTRAIN
Arrayformula, an example for number 5, change to 500.
=ArrayFormula(IFERROR(
vlookup(
(TRANSPOSE(ROW(INDIRECT("a1:a"&ROUNDUP(COUNTA(A:A)/5))))-1)*5 + ROW(INDIRECT("a1:a"&5)),
{ROW(A:A),A:A},2,)
))
ROUNDUP(COUNTA(A:A)/5 the number of columns. Up because the last column may contain less than N rows.
TRANSPOSE(...)*5 + ROW(INDIRECT("a1:a"&5)) to get matrix of numbers.
Matrix:
1 6 11 16
2 7 12 17
3 8 13 18
4 9 14 19
5 10 15 20
{ROW(A:A),A:A} to get the number of a row and value to return
vlookup to return a value
IFERROR to show "" if error.
Having an arbitrarily long column implies you'll need arbitrarily many columns for the split, and spreadsheet formulas cannot create new columns. So the best we can is to use all columns available.
Assuming the data column begins with cell A1, and the upper left corner of the range in which it should be split is B1, the following formula will work, if you fill the first 500 rows of the sheet with it:
=offset($A$1, row()-row($B$1) + 500*(column()-column($B$1)), 0)
Otherwise, change A1 and B1 to the top source and upper-left corner of destination.
Explanation: the offset moves from A1 down by the specified amount, which increments by 1 with every row and by 500 with every column.
You could also use this formula:
=ARRAYFORMULA(
TRIM(
SPLIT(
TRANSPOSE(
SPLIT(
QUERY(
<long_column_range> & "," & IF(
MOD(1, <columns>) = 0, "|", ""
),, 9^9
), "|"
)
), ","
)
)
)
where:
<long_column_range> is the range of the long column that you want to split (e.g. A1:A) and
<columns> is the number of columns that you want for the long column to be split into.
Taken from this article.

Resources