Looping through a set of google sheet values - google-sheets

I have 2 sets of data. One is tank names
Tank Name
A1
A2
B1
B2
and the next is ON/OFF Data
ON/OFF
0
1
1
1
1
1
0
0
1
1
1
1
1
1
1
0
0
1
1
1
0
1
1
Now the result I am looking is, when the ON/OFF is 1 then the first tank is to be mentioned: when it's 0, no tank to be mentioned. Once all the tanks are mentioned,then it should again start from the first tank ie A1.But if 0 comes in between then it should start again from A1 .. like this
Result expected
0
1 A1
1 A2
1 B1
1 B2
1 A1
0
0
1 A1
1 A2
1 B1
1 B2
1 A1
1 A2
1 B1
0
0
1 A1
1 A2
1 B1
0
1 A1
1 A2
You can check the google sheet here : Scenario 2 https://docs.google.com/spreadsheets/d/1SP2SfA-bzzhHgfrvpyUIkeQfUykata0oHxyD-x69yxE/edit?usp=sharing
Hope to get some help to get this solved.
Thanks

Edit
Single formula solution:
=FILTER(IF(B1:B=0,"",VLOOKUP(IFERROR(VLOOKUP(SUMIF(ROW(B1:B),"<="&ROW(B1:B),B1:B),{ROW(INDIRECT("a1:a"&COUNTIF(B:B,1))) , TRANSPOSE(SPLIT(TEXTJOIN("",1,TRANSPOSE(TEXT(ROW(INDIRECT("a1:a"&MAX(LEN(SPLIT(TEXTJOIN("",1,B1:B),"0")))))*(LEN(SPLIT(TEXTJOIN("",1,B1:B),"0"))>=ROW(INDIRECT("a1:a"&MAX(LEN(SPLIT(TEXTJOIN("",1,B1:B),"0")))))),"0"","";;"))),",")) },2,),0),{row(INDIRECT("a1:a"&COUNTIF(B1:B,1))) , VLOOKUP(MOD(ROW( INDIRECT("a1:a"&COUNTIF(B1:B,1)) )-1,COUNTA(A1:A))+1,{ROW(A1:A)-row(A1)+1,A1:A},2,)},2,)),B1:B<>"")
Two formulas will do it.
#1 in C1. For cumulative sum with a loop:
=Filter(IFERROR(VLOOKUP(SUMIF(ROW(B1:B),"<="&ROW(B1:B),B1:B),{ROW(INDIRECT("a1:a"&COUNTIF(B:B,1))) , TRANSPOSE(SPLIT(TEXTJOIN("",1,TRANSPOSE(TEXT(ROW(INDIRECT("a1:a"&MAX(LEN(SPLIT(TEXTJOIN("",1,B1:B),"0")))))*(LEN(SPLIT(TEXTJOIN("",1,B1:B),"0"))>=ROW(INDIRECT("a1:a"&MAX(LEN(SPLIT(TEXTJOIN("",1,B1:B),"0")))))), "0"","";;"))),",")) },2,),0),B1:B<>"")
#2 in D1. For the result:
=FILTER(IF(B1:B=0,"",VLOOKUP(C1:C,{row(INDIRECT("a1:a"&COUNTIF(B1:B,1))) , VLOOKUP(MOD(ROW( INDIRECT("a1:a"&COUNTIF(B1:B,1)) )-1,COUNTA(A1:A))+1,{ROW(A1:A)-row(A1)+1,A1:A},2,)},2,)),B1:B<>"")
References:
Counters Lab
Array Formulas Lab

You can do it most easily with a helper column
=if(B4=1,if(B3=0,0,mod(E3+1,4)),"")
starting in E4 then
=if(E4<>"",index(A$4:A$7,E4+1),"")
starting in F4.
Here's one way of doing it with a single non-array formula:
=IF(B4=1,INDEX(A$4:A$7,MOD(SUM(B4:INDEX(B:B,MAX(INDEX(IF(B$4:B4=0,ROW(B$4:B4)),0)),0))-1,4)+1),"")
in (say) G4 and pulled down.
NB both of these assume that the sequence in column B starts with a zero and would need adjustment if this is not the case.
An array formula is also possible:
=ArrayFormula(if(B4:B=1,vlookup(mod(sumif(row(B4:B),"<="&row(B4:B),B4:B)-sumif(row(B4:B),"<="&vlookup(row(B4:B),if(B4:B=0,row(B4:B)),1),B4:B)-1,4)+4,{row(4:7),A4:A7},2,false),""))
EDIT
Probably the easiest way to get it to work when the first row of on/off data contains a 1 is to include the header row in column B and use n() to treat it as zero so the helper column formula is
=if(B4=1,if(n(B3)=0,0,mod(E3+1,4)),"")
and the non-array formula is
=IF(B4=1,INDEX(A$4:A$7,MOD(SUM(B4:INDEX(B:B,MAX(INDEX(IF(n(B$3:B4)=0,ROW(B$3:B4)),0)),0))-1,4)+1),"")
The array formula works without any change. This is for the fortuitous reason that, while the second Vlookup will fail with #N/A if there are no zeroes in column B before the current row, when this is passed to Sumif you get a zero result which is what you need.

Related

Google Sheets: Query and list the last 5 values in a column if the column contains a number

I want to use Sparkline for a spreadsheet to show a trend of the last 5 soccer matches, where A and B are the goals, and C are the resulting points.
In column C, the points are only generated if values are entered for the goals and goals conceded, i.e. the columns are not empty.
A (Goals)
B (Conceded)
C (Points)
4
4
1
4
4
1
4
4
0
3
4
4
1
0
4
0
As you see, in row 3, column c is empty.
What I basically try to achieve, is to create a list where the last 5 entries which are not empty / null, are listed:
C (Points)
1
1
3
1
0
Is used this formula, but it somehow does not work
=query(J15:J114,"select * offset "&count(J15:J114)-5)
shorturl.at/gHPY9 (example result picture)
Tried to find a solution myself, but am stuck.
Best,
Feal
Use query() with a where clause, like this:
=query(
J15:J114,
"where J is not null
offset " & max(0, count(J15:J114) - 5),
0
)

Use MATCH to dynamically generate a cell reference for a formula

I have a spreadsheet containing a list of candidates and scores in different topics.
For example candidate 01 scored 1,2,3,4 in areas A,B,C,D respectively.
a b c d e
1 ID A B C D
2 01 1 2 3 4
3 02 2 4 5 6
4 03 3 3 7 9
I am trying to create a dashboard with an overview of data from different areas and I would like to produce a summary of the number of times has achieved each score from 1 - 9 in all possible topics.
a b c d e f g h i j k
1 ID #9 #8 #7 #6 #5 #4 #3 #2 #1
2 03 1 0 1 0 0 0 2 0 0
3 01 0 0 0 0 0 1 1 1 1
4 02 0 0 0 1 1 1 0 1 0
It's straightforward enough to use a countif =COUNTIF(scores!c2:c,9) etc in each cell but I cannot guarantee the position of the candidate in the dashboard sheet therefore some form of lookup is required.
=MATCH(B2,scores!A1:E,0) used in dashboard will retrieve for me the position of candidate 03 in scores as 2.
If I could then insert that value into my countif formula I would be able to dynamically assign the required row position for my countif cell reference but I cannot work out how to or even if this is possible.
(I did consider doing this as a query but as the data spans rows rather than columns I cannot see how this would work either).
Try this:
I use here index and match formulas to get right row from the input table.
Then I use frequency function to count number of occurences.
I deal with order of rows using sort formula, but it is not necessary.
All the formulas and working example are available here:
https://docs.google.com/spreadsheets/d/1mtjHq1OCU3zgn3P9Ykm0M1EOlbjWkKI-G7Z1XN5t6Qw/copy

Is there a way to use same field as rows and columns in google sheets to count unique occurrence between columns?

Looking to convert
Task id
John
Jan
Juliet
1
1
1
0
2
1
0
1
3
0
1
1
4
0
0
1
5
0
1
1
6
1
1
0
7
0
1
0
8
1
0
0
9
0
1
1
10
1
1
0
To
John
Jan
Juliet
John
3
1
Jan
3
3
Juliet
1
3
I have set up a new sheet ("Erik Help") in your sample spreadsheet.
In B1:
=SORT(FILTER(Sheet1!B1:1,Sheet1!B1:1<>""))
This simply fills the top row with your names list, sorted alphabetically.
In A2:
=TRANSPOSE(SORT(FILTER(Sheet1!B1:1,Sheet1!B1:1<>"")))
This fills A2 down with the same names list as above, just vertically.
In B2 is the main formula for the grid (which is then dragged over and down):
=ArrayFormula(IF( ($A2="") + (B$1="") + ($A2=B$1),, SUM(MMULT(IF((FILTER(Sheet1!$B$2:$L,Sheet1!$A$2:$A<>"")=1) * (Sheet1!$B$1:$L$1=$A2),1,0), SEQUENCE(COLUMNS(Sheet1!$B$1:$L$1),1,1,0)) * MMULT(IF((FILTER(Sheet1!$B$2:$L,Sheet1!$A$2:$A<>"")=1) * (Sheet1!$B$1:$L$1=B$1),1,0), SEQUENCE(COLUMNS(Sheet1!$B$1:$L$1),1,1,0)))))
The first ( ) + ( ) + ( ) tests three OR conditions. If any is true, the cell will be left blank. This is what allows the formula to be dragged all the way right and down without throwing errors and, in essence, "waiting" for new data from the first two formulas above that it can process.
The rest of the formula is too complex to warrant full explanation (e.g., how MMULT works in detail), this being a volunteer-run site. (Writing the formula took more time than I generally spend in a day on this or other forums.) But here's the gist.
Two grids — each formed by an MMULT (matrix multiplication) — are SUMmed. The first MMULT will produce a grid the same size as the Sheet1 grid, filled with 1 only if two conditions are met: that there was already a 1 in that slot and that the name above matches the name to the right in the "Erik Help" grid. Otherwise, the result for that slot is a zero. The second MMULT forms the same size grid based on the same conditions, only this time it gets a 1 only if there is already a 1 and the name above matches the name above the cell in "Erik Help." These two grids are multiplied, and if the product is a 1, we know that BOTH names had a 1 there. Once SUMmed, we get the count of shared projects for those two names.
As this formula is dragged, cell references not locked with a dollar sign will adjust, so that two different names will be compared by the two MMULT grids.
Because this solution requires comparing arrays with arrays with arrays, I don't currently see how a further array solution is possible, hence the need for the formulas to be dragged. That is, each of these formulas is already jam-packed with array processing.
Again, the formula is currently dragged all the way to Column Z and down to Row 200. However, it only references up to Column L (which is as far as your current names list goes). If your real world application has more names and thus carries over past Column L, the easiest way to change all of the formulas at once is this:
Go to the "Erik Help" sheet (which you can, of course, rename as you like).
Hit Ctrl-H to open the Find/Replace dialog box.
Enter $L in the FIND field and $? in the REPLACE field (where ? will be the new column to which you want the results to extend, e.g., $M or $P, etc.)
Choose "This sheet" from the "Search" drop-down.
Check the box next to "Also search within formulas."
Click the "Replace all" button.
If the data set shrinks or grows again, do the same steps, just changing the old furthest column reference for the new furthest column reference.
Here is a super-simple way of doing it which just changes the pair of columns selected in the countifs as the formula moves across and down by relative addressing:
=countifs(index($B$2:$D,0,row(A1)),1,index($B$2:$D,0,column(A1)),1)
pulled down and across.
Attempt at more general solution.
The question is tagged pivot-table. Although a pivot table approach seems useful, the data is in exactly the wrong format to achieve it. The task would be to transform the data from ones and zeroes to column numbers so
1 1 0 => 1 2
1 0 1 => 1 3
1 1 1 => 1 2, 1 3 and 2 3.
This can be achieved by generating pairs of numbers as follows and performing a lookup in the original data:
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
The formulas to generate these sequences are
=ArrayFormula(quotient(mod(sequence(90,1,0),9),3)+1)
and
=ArrayFormula(mod(sequence(90,1,0),3)+1)
(9 because there are 3X3 pairs per row of data, 90 because there are 10 rows of data).
The following generates a lookup for each row of data
=ArrayFormula(quotient(sequence(90,1,0),9)+1)
Putting all this together and wrapping it in a pivot query gives
=ArrayFormula(query({vlookup(quotient(sequence(90,1,0),9)+2,{row(B2:D),B2:D},quotient(mod(sequence(90,1,0),9),3)+2,0)*(quotient(mod(sequence(90,1,0),9),3)+1),
vlookup(quotient(sequence(90,1,0),9)+2,{row(B2:D),B2:D},mod(sequence(90,1,0),3)+2,0)*(mod(sequence(90,1,0),3)+1)},
"select count(Col1) where Col1<>0 and Col2<>0 group by Col1 pivot Col2"))
The formula can be generalised to different numbers of rows and columns.

Create single formula for several different lines (array) (Google Sheets)

In the AD column I have this sequence of values:
2
3
4
These values refer to rows in a column on another page.
In each line in AE column I use this formula:
=IF(AD1="","",IFERROR(SUM(FILTER(INDIRECT("'Registro Geral'!O2:O"&AD1)/100,REGEXMATCH(INDIRECT("'Registro Geral'!H2:H"&AD1),SUBSTITUTE(SUBSTITUTE(JOIN("|",$V$1:$V$4),"||",""),"|||",""))=TRUE))))
=IF(AD2="","",IFERROR(SUM(FILTER(INDIRECT("'Registro Geral'!O2:O"&AD2)/100,REGEXMATCH(INDIRECT("'Registro Geral'!H2:H"&AD2),SUBSTITUTE(SUBSTITUTE(JOIN("|",$V$1:$V$4),"||",""),"|||",""))=TRUE))))
=IF(AD3="","",IFERROR(SUM(FILTER(INDIRECT("'Registro Geral'!O2:O"&AD3)/100,REGEXMATCH(INDIRECT("'Registro Geral'!H2:H"&AD3),SUBSTITUTE(SUBSTITUTE(JOIN("|",$V$1:$V$4),"||",""),"|||",""))=TRUE))))
In short, this formula is getting a running Sum of values in the other sheet based on whether or not the corresponding cell in another column of the same sheet appears in a set of values.
When I try to add ARRAYFORMULA so that I don't have to have a formula on each line, leaving only in AE1, the values that return on all lines are exactly the same value.
Test Formula Fail:
=ARRAYFORMULA(IF(AD1:AD="","",IFERROR(SUM(FILTER(INDIRECT("'Registro Geral'!O2:O"&AD1:AD)/100,REGEXMATCH(INDIRECT("'Registro Geral'!H2:H"&AD1:AD),SUBSTITUTE(SUBSTITUTE(JOIN("|",$V$1:$V$4),"||",""),"|||",""))=TRUE)))))
Link to Spreadhseet example:
https://docs.google.com/spreadsheets/d/1qIv6KnLv-EwJQXRrk7ucuqY-XuJhkIHOCtih9FpAg6U/edit?usp=sharing
You're trying to do a running summation on O based on whether the corresponding value in the H column appears in the Filtered values.
We can do this with a matrix multiplication using a lower-triangular matrix and the listed values, selecting which ones to zero out based on certain conditions using IF.
=ArrayFormula(MMULT(
N(SEQUENCE(D2)>=SEQUENCE(1,D2)),
ARRAY_CONSTRAIN(
IF(
('Registro Geral'!O2:O<>"")*
IFNA(MATCH('Registro Geral'!H2:H,V:V,0)),
'Registro Geral'!O2:O
)/100,
D2,
1
)
))
Why this works
The lower-triangular matrix looks like
1 0 0 0 0 ... up to N columns
1 1 0 0 0
1 1 1 0 0
1 1 1 1 0
1 1 1 1 1
... up to N rows
The Column you want to sum looks like
Value 1
Value 2
...
Value N
So when you multiply the two, you get a new matrix of dimension N x 1:
Value 1
Value 1 + Value 2
...
Value 1 + ... + Value N
If we don't want to sum a value, then we can zero it out with a conditional so that it never gets added.

Negative References or reversing order of column for DATEDIF

I have a ascending sorted list of irregular dates in Column A:A:
A B C D (A:A,A2:A) E (A:A,A3:A)
2017-11-09 10 10 NA NA
2017-11-10 11 21 1 NA
2017-11-14 15 36 4 5
2017-11-15 22 58 1 5
Column C:C is a rolling sum of B:B. I'm trying to get arrayformula in D:D/E:E to find the datedif between current row (starting date) and X rows above (end date):
=ArrayFormula(DATEDIF(B:B-(X Rows),B:B,"D"))
The goal is to find range of change in D:D over X amount of days:
D:D - D:D-rowX / datedif (A:A-rowX, A:A)
i.e for 2 days on row C4:
(C4-C2) / datedif(C4-2,C4,"D")
(58-21) / datedif(C2,C4,"D")
37 / 5 = 7.4
for 5 days on row C10:
(C10-C5) / datedif(C10-5,C10,"D")
for 15 days on row C20:
(C20-C5) / datedif(C20-15,C20,"D")
I'm trying to calculate X for 1,2,3,4,7,28 rows up which means the array has to start that 1,2,3,4,7,28 rows down.
Right now, the array bugs out to bad reference because the first starting date is DATEDIF(B-X,B1,"D") where B-X is a invalid negative reference. Arrayformulas with bad values instead of bad references seems to just skip past errors and starts working once input are valid. But I can't figure out how to skip bad references. I've tried forcing start date with INDIRECT but can't get it to recognize value as a date. I also tried DATEDIF(B:B, B:B+X,"D"), which spits out the correct numbers but results are offset by X rows. I've tried reverse sorting A:A, =ArrayFormula(if(len(A:A),DATEDIF(SORT(A2:A,1,0),SORT(A:A,1,0),"D"),"")) it produces a reverse orders list of correct answers that I can't figure out how to flip back.
Seems like I'm missing something obvious?
EDIT: tried to clarify original post
Is there a easy way to displace an entire column?
Alternative Solution?
The formula roughly works but is not aligned to the correct row:
C D E
1 2 3
1 2 3
1 2 3
1 2
1
I just need it to display
C D E
1
1 2
1 2 3
1 2 3
1 2 3
To get things aligned, I can put in cell on row2 of Column F:
=array_constrain(ARRAYFORMULA(D:D),COUNT(A:A)-2,1)
Or cell in row3 of Column G:
=array_constrain(ARRAYFORMULA(E:E),COUNT(A:A)-3,1)
But if I try trigger teh formula from row1 via:
=arrayformula(if(row(A:A)>=2,array_constrain(D:D,COUNT(A:A)-2,1)))
It label everythign >=2 row false and still render D:D without displacing the cells the proper number of rows:
C D
1 false
1 2
1 2
1 2
1
EDIT: I'm closing the request, ended up just using vlookup(B:B-X) which provided an approximate enough result to work for my needs.
Short answer
Add the following formula to D1
=ArrayFormula({"N/A";ARRAY_CONSTRAIN(DATEDIF(A:A,A2:A,"D"),COUNT(A:A)-1,1)})
And the following formula to E1
=ArrayFormula({"N/A";"N/A";ARRAY_CONSTRAIN(DATEDIF(A:A,A3:A,"D"),COUNT(A:A)-2,1)})
Explanation
The solution use ARRAY_CONSTRAIN to return just the required result values and use a the array notation to add the required N/A values for the rows that as it don't have a pair to calculate the date difference.
REMARK:
Please note that the DATEDIF functions use the column A for the references as this column is the one that holds the date values.

Resources