Improving a Spreadsheet Formula to be more dynamic - google-sheets

I have a a couple sheets that I want to filter the values of and sum them together. I have a working function:
=SUM(INDEX(Grades!M32:V32,0,B2)+INDEX(Grades!M32:V32,0,C2)+INDEX(Grades!M32:V32,0,D2)+INDEX(Grades!M32:V32,0,E2)+INDEX(Grades!M32:V32,0,F2)+INDEX(Grades!M32:V32,0,G2))
and this is working fine. The problem is it isn't really dynamic and I was wondering if there was a more efficient way to approach this instead of using so many Indexes.
Index is grabbing a horizontal range of numbers from another sheet and getting the needed index position from a small table in another sheet.
Update
I was able to get the formula working how I wanted by inserting an IF statement that would not do the VLOOKUP if one of the cells was empty.
=ArrayFormula(SUM(IF(B2:I2 <> "",VLOOKUP(1,{1,Grades!$M$32:$V$32},B2:I2+1))))

It looks a bit strange, but this is one way:
=ArrayFormula(SUM(VLOOKUP(1,{1,Grades!M32:V32},B2:G2+1,0)))
In the VLOOKUP, 1 is the value you are searching for, {1,Grades!M32:V32} is the array in which you are searching, B2:G2+1 is the column index (or rather, indices) you wish to return, and 0 dictates that you require an exact match.
{1,Grades!M32:V32} constructs a horizontal, one-row array that has 1 in the left-most element, with the values in Grades!M32:V32 to the right of it.
VLOOKUP will search down the left-most column of that array. It will always "find" the 1 that it is searching for in the left-most column, because we have purposely manufactured that.
Where the action really happens is in the third argument, where we return the columns in that manufactured array corresponding with the values in B2:G2 (I should add, I assumed that all cells in B2:G2 are populated - it will return the wrong result if any are blank). The +1 is to account for the extra element (the 1) we tacked on to the left of the lookup array.

Related

Is there any solution to left the cell empty

i have a sheet along with this question,the formula used in column E2 is : if(and(d2>=0,d2<=2),5. So when the column is blank it gives the value 5 My query is can we left the "E" column blank when there is no value in "D". ??? 5 must displayed only if there score between 0 & 2.
https://docs.google.com/spreadsheets/d/1XpdXcWDReB8TGvZ6ocALAilVPLDKzZXvd90YhNos0Io/edit?usp=sharing
Iker. I've added a sheet with two approaches.
If you want to drag the formula, just set an initial IF that rules out blanks like this:
=if(D2="","",if(and(D2>=0,D2<=2),5,if(and(D2>=3,D2<=4),0)))
I placed this into my sheet, E2, and dragged down as you were doing.
However, this is a great example of where array formulas are handy. An array formula can "run" your whole column from just one cell. I placed the following array formula into cell I1 of my sheet:
=ArrayFormula({"POINT";IF(H2:H="","",IF((H2:H>=0)*(H2:H<=2),5,IF((H2:H>=3)*(H2:H<=4),0,"")))})
First, keep in mind that array formulas must have unused space below them in order to fill in results. If you type anything manually below an array formula, inside the range it is trying to work on, you'll get an error. If you do want to put other data below an array formula, just limit the range in the array formula (e.g., change every H2:H to H2:H6 or whatever the end of that data range might be).
ArrayFormula() tells Google Sheets to apply this formula to the entire range in the formula. Since the range in the formula is H2:H, every cell in I2:I will be "reserved" by this array formula.
The curly brackets {} allow us to build another custom array inside the first array.
Since I want a header in I1, I put that header name first in the curly brackets. The semicolon tells the array to put the next part underneath.
The next part may look strange, but it's basically the same as your original formula, except that AND(), OR(), etc., don't work inside arrays. So the logical operators inside arrays are different. In this case, an asterisk * means AND.
The same conditions from your original formula are used here. And if it meets none of those criteria (for instance, if someone entered -1 or 7 or M somewhere in Column H, the last part of the last IF would just assign a blank.
You can use an added IF to your formula
=IF(D2="","", if(and(D2>=0,D2<=2),5,if(and(D2>=3,D2<=4),0)))

How to delete empty cells and shift up in Google Sheets?

Is there a way to delete empty cells in a given range and shift the column up to the desired display as shown below? Closest I came was
=ARRAYFORMULA({A1:C1; TRANSPOSE(SPLIT(TRANSPOSE(QUERY(A2:C,,999^99)), " "))})
which removes empty cells, but splits the first names and surnames into separate cells, which I have not figured out how to avoid. Pfa a made-up sample of current and desired displays:
Current Display
Desired Display
I'm new at this, but I came up with a bit of a brute force method, which may help you.
={
{(A1:C1)};
{FILTER(A2:A100,A2:A100<>"");indirect("N1:N" & 100-counta(A2:A100))},
{FILTER(B2:B100,B2:B100<>"");indirect("N1:N" & 100-counta(B2:B100))},
{FILTER(C2:C100,C2:C100<>"");indirect("N1:N" & 100-counta(C2:C100))}}
Assuming your data block is in columns A1:C100, this formula filters blank cells from each individual column, and then pads each column with blank cells at the bottom, to make the three arrays equal in length/dimension.
Note that in "100-counta(...", the 100 is the expected maximum length of your data column.
This could be calculated, and must be the same for all three columns.
Note also that the first array is horizontal (ends with a semi-colon), followed by the three columns, stacked beside each other (ends with a comma).
Here is a working example.
https://docs.google.com/spreadsheets/d/1MGaqqGrkmIliuAzEqxPtdEVZXWPN2K5W7jFFM-ZnwgE/edit?usp=sharing
If I missed something you were trying to achieve, let me know.
Also, I'm sure that there is a more elegant way to do this, or one not requiring the use of a block of "reserved" blank cells, but I couldn't think of that at the moment.
Edit: The formula as follows also works. But you need to remember to set the "100" value to be equal to the number of rows in your data block, since we pad the columns with the necessary number of blanks rows, after removing the blank cells in each column.
={
{(A1:C1)};
{FILTER(A2:A,A2:A<>"");indirect("N1:N" & 100-counta(A2:A))},
{FILTER(B2:B,B2:B<>"");indirect("N1:N" & 100-counta(B2:B))},
{FILTER(C2:C,C2:C<>"");indirect("N1:N" & 100-counta(C2:C))}}

Working with hierarchical data in Google Sheets

If I have hierarchical data in a Google Sheet as in columns A and B in the example below, how can I write a formula that will fill the corresponding cells in column C with the product of the "parent" value in A1, and the "child" values in column B. That is, The formula in C8 for example, will search upward in column A until it finds the value 5 in A6, then multiplies it by 8, the value in B8.
Obviously I'm trying to avoid having to put the "parent" value in every row in column A.
After a fiddling around and jogging my memory on ArrayFormulas I figured out how to get the result I wanted. Here's the formula I'm using:
=ArrayFormula(index($B$2:$B2,MAX(IF(ISNUMBER($B$2:$B2),ROW($B$2:$B2)))-1,1))
(Note: Row 1 contains headings)
Edit: Explanation of how I arrived at this solution:
Ordinarily, IF(ISNUMBER(cell)), and ROW(cell) would return TRUE/FALSE, or a row number respectively. When used in an array formula and a range of cells as input instead, what you get is a list of TRUE/FALSE values, and row numbers evaluated for each cell in the input range. Wrap MAX around that and it will return the position in those two lists where IF(ISNUMBER()) is TRUE and the row number returned by ROW() is the highest, effectively searching from the bottom of the range.
The absolute reference for the first element in the range to be searched (in this case $B$2) keeps the range anchored to the same starting location when dragging the formula into other cells, while the lower bound of the range (in this case $B2) to be searched grows vertically.
Finally, the INDEX takes the input range, row number returned by the above (-1 row because of the header) and column position (1, since there is only one column) in order to return the desired value.
One way you could do this would be to associate each value in column B with a category or key that can be used to lookup the value for A in a separate table. This abstracts it somewhat, so you can change the values for the A column without having to have them in every row, but there's no empty cells.
i.e.
and lookup table:
In column C
= VLOOKUP($A1, <range for category lookup table>, 2, 0) * $B1
(And then this formula can be filled down)
More on VLOOKUP in Google Sheets here
Alternatively I suppose you could use a formula to find the last non-empty row in column A, or something along those lines, but this is more of a hack than a proper way to structure your data. Tables aren't really designed to be used in a hierarchical fashion like what you've shown. But they can easily represent hierarchical data using techniques like what I've suggested.

How to average the last seven values in a column?

I am trying to find the average of the seven most recent entries in a row, as seen in
this
spreadsheet.
I found a few questions similar to mine, but I am still pretty confused on how the answers work. The questions similar to mine can be found on the left side of my spreadsheet.
I think that the formulas would work for me with a few simple adjustments of which values to use, but I can't seem to figure it out. I would really appreciate if someone could explain one of the existing answers or come up with another one that works.
The spreadsheet is updated daily, so I need something that would continue to work as more and more data is added to the column.
Try:
=round(AVERAGE(OFFSET(H1,MAX(ARRAYFORMULA(ROW(H:H)*--(H:H<>"")))-7,,7)))
here's working sample
Explanation
We are getting the last non empty row: MAX(ARRAYFORMULA(ROW(H:H)*--(H:H<>"")))
Then with offset formula we are getting the range of last 7 cells in a column.
And then just use AVERAGE.
More info
You may find more info about finding the last non empty row here:
Selecting the last value of a column
Another way is to use INDEX and MATCH. The first match finds the position of the last number in the range and takes 6 away from it: the second match finds the position of the last number in the range. Passing it through the INDEX function gives a reference that you can use to give a range of 7 cells for AVERAGE to work on.
=average(index(H:H,match(999,H:H)-6):index(H:H,match(999,H:H)))
So my answer is like your Link2
The big snag here is if you have a text cell in the range (like "Nothing") it is much more difficult to work out which cell to start from to get an average of 7 cells. I think I know how to do it in Excel using OFFSET but offset doesn't seem to work in the same way in Google Sheets.
However I can see there is a solution to this in your Link3 which should work for you if you change A:A to H:H and SUM to AVERAGE. I have tested it on the average of the last ten cells which includes a "Nothing" cell:
=ArrayFormula(AVERAGE(QUERY(SORT(H:H,ROW(H:H)*ISNUMBER(H:H),0),"select * limit 10")))
and it gives the correct answer 61.8.
The way array formulas work in general is that instead of passing a single value to a function you pass a whole range or array (a list of values) and the function processes them one by one. The above formula takes the whole column H:H and sorts it on the row numbers in descending order but those cells which don't contain a number give zero in the multiplication and are sorted to the bottom. Then the query takes the top (in my case) 10 cells and passes them to AVERAGE.
BTW this doesn't have to be declared as an array formula: this also works
=AVERAGE(QUERY(SORT(H:H,ROW(H:H)*ISNUMBER(H:H),0),"select * limit 10"))

Working with OFFSET and SPLIT together to get an array of looked-up cells

I'm unable to get OFFSET to return an array of data in Google Sheets. For example in the same sheet, I have a player table which eats an animal, the eats column stores the index of the animal. I want to add up all weights.
This is what I came up with (the example numbers might not be exactly right) but it only works with the first split value:
=SUM(IFERROR(OFFSET($H$11,SPLIT(D6,","),0,1,1),0))
Assuming User A is in B2 and your other table is a Named Range (1), please try:
=ArrayFormula(sum(vlookup(split(C2,","),NamedRange1,3,0)))

Resources