ArrayFormula, Google Spreadsheet - google-sheets

This seems to be a simple problem that I cannot get around. I have the following formula (works fine).
=MEDIAN(FILTER('Filtered-Data'!$D$4:$D,'Filtered-Data'!$C$4:$C=B3))
What I want is to use ArrayFormula to get a column wise result for the range B3:B instead of just B3
Can this be done?

First idea was to use Google QUERY function, however it does not support standard SQL SELECT ... WHERE... IN (valA,valB...) clause. However thing you want is achievable with ARRAYFORMULA. The trick is to match appropriately two columns, handle errors, and apply appropriate filtering (multiline for readability):
=MEDIAN(FILTER(Filtered-Data'!$D$4:$D,
ARRAYFORMULA(IF(IFERROR(MATCH
(Filtered-Data'!$D$4:$D,'Filtered-Data'!$C$4:$C=B3:B,0),0)>0,TRUE,FALSE))))
Explanation:
ARRAYFORMULA(MATCH(col1,col2,0)) finds in array first row containing value matching criteria, 0/1 determines whether matching starts from top or bottom. For standalone use, MATCH stops after producing first result. Applying ARRAYFORMULA on MATCH gets us close to what we want - it produces an array of results. However, if item is not matched, error is returned, so you get something like below, in a column:
N/A
2
3
1
3
2
N/A
N/A
N/A
1
3
These N/A stuff will do us no good, since we always want some kind of row number. Here comes IFERROR, which replaces all N\A with good ol' "0": IFERROR(MATCH(col1,col2,0),0)
Google Spreadsheet never counts rows from "0" (it starts from "1", only offsets are zero-based), so this is pretty safe unless your data contains "0" - than change it to anything else safe for your case.
Since FILTER expects in filtering_criteria single column array of booleans or expression that evaluates to array of booleans (https://support.google.com/drive/table/25273?hl=en ) we need to make sure ARRAYFORMULA produces such array of booleans. IF comes in handy - always produces either TRUE or FALSE: IF(IFERROR(MATCH(col1,col2,0)>0,TRUE,FALSE)
Now re-apply ARRAYFORMULA on that stuff, to work on array & render an array result instead of single result: ARRAYFORMULA(IF(IFERROR(MATCH(col1,col2,0)>0,TRUE,FALSE)) and put it inside FILTER... voila, it works.
For reference see: http://productforums.google.com/forum/#!topic/docs/PpnZinkLzQs

Related

How can I get the last numerical value value in a column in Google Sheets?

I need to find the last numerical value in a column. I was using this formula to get the last value in column G, but I made some changes and it no longer works: =INDEX(G:G, COUNTA(G:G), 1). My column now looks like this:
645
2345
4674.2345
123.1
"-"
"-"
"-"
...and the formula returns "-". I want it to return 123.1. How can I do this?
There are many ways to go about this. Here is one of them:
=QUERY(FILTER({G:G,ROW(G:G)},ISNUMBER(G:G)),"Select Col1 ORDER BY Col2 Desc LIMIT 1")
FILTER creates a virtual array of only numeric values in G in the first column and the row of those numeric values in the second column.
QUERY returns flips the order by row number and returns only the new top value from the first column (which winds up being your last numeric value in the original range).
However, if your numeric values start at G1, and if there are only numeric values up to where you start adding hyphens in cells, you could just alter your original formula like this:
=INDEX(G:G,COUNT(G:G))
This would work because COUNT only counts numeric values while COUNTA counts all non-null values (including errors BTW).
Not to take anything away from the accepted answer, but I've been working on this a bit lately in relation to this for the never-ending last row discussion and thought I'd share some potential similar solutions. These ideas are inspired by a pattern of google sheet array questions that seem to be coming up more often. I am also intentionally using different ways to do the same thing just to give people some ideas (i.e. left and Regex).
Last Row that is...
Number: =max(filter(row(G:G),isnumber(G:G)))
Text: =max(filter(row(G:G),isText(G:G)))
An error: =max(filter(row(G:G),iserror(G:G)))
Under 0 : =max(filter(row(G:G),G:G<0))
Also exists in column D: =max(filter(row(G:G),ISNUMBER(match(G:G,D:D,0))))
Not Blank: =max(filter(row(A:A),NOT(ISBLANK(A:A))))
Starts with ab: =max(filter(row(G:G),left(G:G,2)="ab"))
Contains the character !: =max(filter(row(G:G),isnumber(Find("!",G:G))))
Starts with a number: =max(filter(row(G:G),REGEXMATCH(G:G,"^\d")))
Only contains letters: =max(filter(row(G:G),REGEXMATCH(G:G,"^[a-zA-Z]+$")
Last four digits are upper case: =Max(filter(row(G:G),REGEXMATCH(G:G,"[A-Z]{4}$")))
To get the actual value (which I realize was the actual question), just wrap an index function around the Max function. So for this question, a solution could be :
=Index(G:G,max(filter(row(G:G),isnumber(G:G))))

Google Sheets SUMIFS different criteria with checkbox

i've the following formula the problem i've is, this isn't working as it should be.
=SUMIFS(E9:14,$I$16:$I,FALSE(),$H$16:$H,G8)
E9:E14 is the part which should be summed up when the checkbox in I16:I = FALSE and if the name matches in H16:H from G8. My problem is I am getting this error
The array arguments of "SUMIFS" vary in size
My question would be, how do I get this exact formula to work? Exactly these areas have to be covered and cannot be changed, otherwise everything else is broken.
EDIT: Added example spreadsheet
https://docs.google.com/spreadsheets/d/1DdTSZAfGTpoeun3k2qqkDMG1jnaUaSz6wgSf2heIIDI/edit?usp=sharing
You need to adjust your ranges. Here's how =SUMIFS() works and then you'll see why you need to adjust the function.
=SUMIFS() looks for ranges and then applies the logic. So when you are telling the function to summarise E9:E14 it interprets it as:
SUM(E9,E10,E11,E12,E13,E14)
provided the following conditions. The conditions will tell the function whether to include each of the components (i.e. E9,...,E14).
Whether a condition is met or not is decided using a simple boolean (true/false) array. This could for example be I9:I14=FALSE which is interpreted as the array
{IF(I9=FALSE),IF(I10=FALSE),...,IF(I14=FALSE)}
resulting in an array similar to this:
{TRUE,TRUE,FALSE,FALSE,FALSE,TRUE}
(assuming the conditions I9, I10 and I14 are met but not the other three. The same is done for the second condition (the values in column H being equal to the value in G8, resulting in another array similar to this:
{TRUE,FALSE,FALSE,TRUE,FALSE,TRUE}
(assuming that only the values in H9, H12 and H14 are equal to G8.
When the function compares the two condition arrays and returns an aggregate array similar to this:
{TRUE,FALSE,FALSE,FALSE,FALSE,TRUE}
because only for the first and the last value the conditions are met. Therefore the =SUM function becomes like this:
SUM(E9,FALSE,FALSE,FALSE,FALSE,E14)
where FALSE = 0 so it returns
=SUM(E9,E14)
Here's where you get into trouble
You try to pass the function conditional arrays that are of a different size to the sum array (E9:E14), in effect asking it to compare apples and the age of your neighbour. What you need to do is to create the calculation you have in column E in a new column in rows 24 down and use that as the sum range in =SUMIFS().

Check if data that satisfies multiple criteria exists in both sheet 1 and sheet 2

My table contains 2 sheets with a different number of columns. I want to add a column that will display true or false (or any other 2 opposite values ) for each row depending on whether this row satisfies 2 criteria which are: sheet1!col1=sheet2!col1 and sheet1!col2=sheet2!col2.
You'll find an illustration below.
I've tried using
ARRAYFORMULA(VLOOKUP(A1&B1, {Sheet1!A1:A4&Sheet1!B1:B4,Sheet1!C1}, 3))
but I get an error message
vlookup evaluates to an out of bound range
So I wanted to try
QUERY({Sheet1!A1:B4,A1:B5}, "Select C where ")
but I couldn't figure out how to write the condition where (sheet1)col1=(sheet2)col1 & (sheet1)col2=(sheet2)col2 and I also don't know if I can work with tables of different dimensions. I finally tried
=MATCH(A1&B1,{Sheet1!A1:A&Sheet1!B1:B})
but it always returns 1.
Any idea please?
Sheet 1
Sheet 2
Your first formula is almost right. You are getting the error message because there is only one column in the curly brackets so you have to change it to
=ArrayFormula(vlookup(A1&B1,{Sheet2!A:A&Sheet2!B:B},1,false))
and add the 'false' to make sure it only does exact matches.
To make the query work you need the right syntax to access cells in the current sheet:
=query(Sheet2!A:B," select A,B where A='"&A1&"' and B='"&B1&"'")
To make the match work, you need to enter it as an array formula and add a zero to specify exact match:
=ArrayFormula(MATCH(A1&B1,{Sheet2!A:A&Sheet2!B:B},0))
However I would take flak from my colleagues if I didn't point out that there is an issue with the vlookup and match as shown above - toto&moto would match with not just toto&moto, but also with tot&omoto etc. The way round this is to add a separator character e.g.
=ArrayFormula(vlookup(A1&"|"&B1,{Sheet2!A:A&"|"&Sheet2!B:B},1,false))
=ArrayFormula(MATCH(A1&"|"&B1,{Sheet2!A:A&"|"&Sheet2!B:B},0))
These still need some tidying up if they are to report Yes and No, and also not to give false positive on blank rows - also the vlookup and match can be written as self-expanding array formulas - but that is the short answer to the question.

Pick the greatest number in a range that is also less than the corresponding number in another range's row

I have two sets of data in columns A and B. I would like to pick the maximum value from column A which is also less than the value in the corresponding row in column B. I think I ought to be able to do this with the MAXIFS function but all the examples I can find compare against static values. I tried these options
=MAXIFS(A1:A10, B1:B10, "<")
=MAXIFS(A1:A10, B1:B10, A&"<"&B)
but neither of them worked as expected. In the first case, it is always 0 suggesting the condition is never met, in the second it gives an error.
I know that I could do this by creating a separate region of cells which first filter out the data that doesn't match the conditional and then simply pick the max from what remains but I'd rather do it in a single cell if possible.
Is there a syntax for this comparison and, if so, what is it?
To the best of my knowledge there isn't a way of getting it to work with MAXIFS.
You can write this
=maxifs(A:A,A:A,"<"&B:B)
and it will accept it, but it just uses the first value in column B and doesn't do a side-by-side comparison.
So you have to do it another way e.g. with a combination of Max and If:
=ArrayFormula(max(if(A:A<B:B,A:A)))
or you can use max with a filter or query:
=max(filter(A:A,A:A<B:B))
=max(query(A:B,"select A where A<B"))
=ARRAY_CONSTRAIN(ARRAYFORMULA(
IF(LEN(INDIRECT(ADDRESS(ROW(), COLUMN(B:B))))>0,
IF(INDIRECT(ADDRESS(ROW(), COLUMN(B:B)))<MAX($A$1:$A),
MAX($A$1:$A), LARGE(UNIQUE($A$1:$A), 2)), )), 1, 1)

Index match find closest value with multiple search criteria

I am trying to find a closest absolute value with index match. I looked at several other posts like here but what i am trying to do is a bit different as i want to add multiple search criterias.
As you can see , I am trying to get the absolute closest time for a specific person.
I am using the formula =index(C2:C21,match(F4,B2:B21,-1),match(E4,A2:A21,0)) and I had to copy column B in column C to make my 1st match work. The result is shown in G4. Unfortunately I am struggling to get the correct result.
Effectively I would like use the formula that was posted in the previous post (see link at the top) =INDEX(E2:E21,MATCH(TRUE,INDEX(ABS(D1:D21-I4)=MIN(INDEX(ABS(D2:D21-I4),,)),,),0))
with with a search criteria (the name of the person).
Any help would be much appreciated
Thank you
Thanks #avram
I still end up with some cases where the formula does not work. See below. in G6 and G7 i should get 10:25. (You can ignore column A)
Try this formula in G4,
=index(C$2:C$21, match(min(index(abs(index(C$2:C$21+(B$2:B$21<>E4)*1E+99, , )-F4), , )), if(B$2:B$21=E4, abs(C$2:C$21-F4), 1E+99), 0))
This will work in either google-sheets as a standard (non-array/non-CSE) formula or excel as an array (CSE) formula.
If anyone else wants to tackle this problem with a more elegant formula, you can copy the sample data from this publicly shared google-sheet.
Index match find closest value with multiple search criteria
Perhaps this may exempt a fourth person from retyping the same tired data that the op delivered in image(s).
A very simple approach using a "helper" column with data like:
We want the closest absolute match for larry to 10:15 AM. We enter larry in E1 and 10:15 AM in F1
Then in D2 we enter:
=IF(A2=$E$1,ABS(B2-$F$1),"")
and copy downward. (this is the absolute difference for larry) Finally in E2:
=INDEX(B:B,MATCH(MIN(D:D),D:D,0))
With bigger tables having more columns, it is very easy to add additional criteria if needed.
This answer uses Array Formulas which must be entered using CTRL+SHIFT+ENTER. It's kind of complicated, so I'll do my best to explain and will revise if necessary. Here's a screenshot:
Here is the formula in its raw form; names are entered in column A, Times in Column B.
=INDEX(B1:B7,MATCH(MIN(IF(A1:A7=D2,ABS(E2-B1:B7),"")),IF(A1:A7=D2,ABS(E2-B1:B7),"")))
As you might suspect, it uses INDEX/MATCH to get the job done, but the key is using an IF statement to generate both the search criteria and the array that the MATCH function searches within. Let's break it down.
Sec 1, Match Search Array
IF(A1:A7=D2,ABS(E2-B1:B7),"")
This creates the Search array for the match function. If the name in D2 (our criteria) is equal to the name in the search array, it return the absolute value of the difference between the criteria time and the time in the array we're searching. Otherwise it returns a blank value. Do not use 0 for this as it will skew the match result.
Sec 2, Match Search Criteria
MIN(IF(A1:A7=D2,ABS(E2-B1:B7),""))
This tells us the smallest value in the above array. We use this value as the search criteria in the MATCH function.
Sec 3, putting 1 & 2 Together
MATCH(MIN(IF(A1:A7=D2,ABS(E2-B1:B7),"")),IF(A1:A7=D2,ABS(E2-B1:B7),"")) This searches for the smallest abs difference defined in Section 2 within the array created in Section 1 and returns the row number.
Sec 4, Indexing the times
=INDEX(B1:B7,MATCH(MIN(IF(A1:A7=D2,ABS(E2-B1:B7),"")),IF(A1:A7=D2,ABS(E2-B1:B7),"")))
This returns the time value from column B in whatever row is identified by the Match function above.
Hopefully this all makes sense. Remember to enter it as an array formula.

Resources