Create serial count in column if adjacent cell is blank (Google Sheets) - google-sheets

I'm trying to create a simple counting ArrayFormula that iterates by one, if adjacent cell is empty (doesn't contain "IGNORE"). E.g. COUNT column here should only count when STATUS <> IGNORE:
ROW STATUS COUNT
______________________
1 IGNORE
2 IGNORE
3 1
4 2
5 3
6 IGNORE
7 IGNORE
8 4
9 5
What ArrayFormula can I use here in cell C1 COUNT?

You can create a custom function and integrate it with ARRAYFORMULA.
Example
Code:
function countNonIgnore(values) {
var tempArr = [];
var ctr = 1;
values.forEach(val => {
if(val[0] == "IGNORE"){
tempArr.push([""]);
}else{
tempArr.push([ctr]);
ctr++;
}
})
return tempArr;
}
Output:
Reference:
Custom Functions in Google Sheets

Option using standard functions:
=ARRAYFORMULA(if(B2:B10<>"IGNORE",COUNTIFS(B2:B10<>"IGNORE",B2:B10<>"IGNORE",ROW(B2:B10),"<="&ROW(B2:B10)),))

If you really need a formula in C1, I would use something like this:
=ARRAYFORMULA(IF(ROW(B:B)=1, "COUNT", IF((B:B<>"IGNORE")*(A:A<>""), COUNTIFS(B:B<>"IGNORE", TRUE, ROW(B:B), "<="&ROW(B:B))-1,)))
If in C2, then
=ARRAYFORMULA(IF((B2:B<>"IGNORE")*(A2:A<>""), COUNTIFS(B2:B<>"IGNORE", TRUE, ROW(B2:B), "<="&ROW(B2:B)),))

Related

Google Sheets: Count number of rows in a column that do not match corresponding row in another column?

Say we have the following spreadsheet in google sheets:
a a
b b
c
d e
e d
How would I build a formula that counts the number of rows in column B that do not match the corresponding row in column A, and are not blank? In other words I want to get the number of rows that changed to a new letter in column B. So in this example the formula should return 2.
Thank you for your help.
UPDATE:
Now suppose I have this spreadsheet:
a a
b b b
c a
d e e
e d e
How would I build on the last formula for the third column, where the value returned is:
(the number of rows in column 3 that don't match the corresponding row in column 2) + (if column 2 is blank, the number of rows in column 3 that do not match the corresponding row in column 1)
and I also don't want to count blanks in the third column.
The value returned in this case should be 2 (rows 3 and 5).
To me it sounds like you could use:
=SUMPRODUCT((B:B<>"")*(B:B<>A:A))
=IFNA(ROWS(FILTER(A:B,
(A:A<>B:B)*
(B:B<>"")
)),0)
FILTER by matching conditions * for AND + for OR.
ROWS counts rows
IFNA returns 0 if nothing was found.
or with QUERY
=INDEX(QUERY(A:B,"select count(B) where B<>A"),2)
Try this:
=ARRAYFORMULA(COUNTA($B$1:$B)-SUM(COUNTIFS($A$1:$A, $B$1:$B,$B$1:$B,"<>")))
I see 2 ways to complete this.
First you could add a function to each row to return 1 or 0 if the value changed and was not blank and then sum results. This unfortunately adds a messy column in your spreadsheet.
=if(A1<>IF(ISBLANK(B1),A1,B1),1,0)
Second you could create a function where you would pass the range as a string.
The call from the worksheet would look like this:
=myFunction("A1:B5")
Then create a script by opening Tools -> Script editor and use something like this
function myFunction(r) {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(r);
var numRows = range.getNumRows();
var areDifferent = 0;
for (let i=1; i<= numRows; i++) {
let currentValue = range.getCell(i,1).getValue();
let cmpValue = range.getCell(i,2).getValue();
if ((currentValue != cmpValue) && (cmpValue != "")) {
areDifferent++;
}
}
return areDifferent;
}

Countif Indirect Google Sheets

I am trying to write a formula that counts the number of times the number 1 appears in cell F1 of all my sheets. My sheets have varying names (18-0100, 18-0101, 18-0102...). I tried the following formula:
=COUNTIF(INDIRECT("'"&"'!F1"),"=1")
It acts unpredictably. It will only return 1 even if it should be more than 1. And when I try to start trying to count 2 instead of 1 it returns 0 and not the correct number.
What am I doing wrong?
Your formula counts only the current sheet.
To get them all you need to enter all sheet names:
The formula for each sheet is:
=(INDIRECT("'"& sheet_name &"'!F1")=1)*1
You can leverage a Google Apps Script to pull this off as well.
From your spreadsheet, go to Tools > Script Editor. Add the code below, then save. The function saved there will be accessible by all other Google apps, including your spreadsheet. You can then use the name of the function in your spreadsheet like you would with any other formula.
function OccurrencesInSheetNames(str) {
var c = 0;
var regExp = new RegExp('[' + str + ']', 'g');
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var sheetnames = [];
for (var i=0; i<sheets.length; i++) {
sheetnames.push([sheets[i].getName()]);
}
for (var i=0; i<sheetnames.length; i++) {
var name = sheetnames[i].toString();
var count = (name.match(regExp) || []).length;
c += count;
}
return c;
}
Now in your cell F1, place the following formula:
=OccurrencesInSheetNames(TEXT(1,0))
You can also replace the 1 in the above formula with a cell reference, if that works better for your needs. (e.g. =OccurrencesInSheetNames(TEXT(C5,0)) if you want to search through your sheet names for the integer number found in cell C5.)
Here's a demo spreadsheet for you to try out.

Create a list in sheet 2 containing column 1&5 from Sheet 1 to Sheet 2 columns 1&2, if Sheet 1 column 3 contains "yes"

I have sheet with 6 columns of data and 100 rows. If Sheet 1, column 3 has the text "yes" in it, I want to copy column 1 to column 1 and column 5 to column 2.
That's not too hard with a simple Match. The problem is I don't want blank rows if column 3 doesn't have "yes" in it. So for example:
Sheet 1:
Steve, Johnson, yes, 5, welder
Ryan, Flag, yes, 3, welder
Joe, Dirt, no, 0, forklift
David, Abraham, yes, forklift
Logan, Gonzales, yes, truck
Sheet 2:
Steve, welder
Ryan, welder
David, forklift
Logan, truck
You can just change the names of the sheets in the getSheetByName functions if you need to.
function summaryList()
{
var ss=SpreadsheetApp.getActiveSpreadsheet();
var mainsht=ss.getSheetByName('Sheet1'); //Change sheetname if needed
var mainrng=mainsht.getDataRange();
var mainrngA=mainrng.getValues();
var sumsht=ss.getSheetByName('Sheet2'); //Change sheetname if needed
var sumA=[];
for(var i=0;i<mainrngA.length;i++)
{
if(mainrngA[i][2]=='yes')
{
sumA.push([mainrngA[i][0],mainrngA[i][4]]);
}
}
if(sumA.length)
{
var sumrng=sumsht.getRange(1,1,sumA.length,sumA[0].length);
sumrng.setValues(sumA);
}
else
{
SpreadsheetApp.getUi().alert('No content in summary list');
}
}

Generate string like Q,R,S...AB where AB is last column in Google Sheet

I have a complex Google Sheet query that works great except when a Google Sheet doesn't have as many columns as I use in my formula.
Here's what the formula looks like now:
=sum(filter(query(INDIRECT("'" & A2 & "'!$A$7:$23"),"select Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH where B='"&C2&"'",0),query(INDIRECT("'" & A2 & "'!$A$7:$23"),"select Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH where B='PROJECT'",0) >=date(2017,1,1),query(INDIRECT("'" & A2 & "'!$A$7:$23"),"select Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH where B='PROJECT'",0) <=date(2017,12,31)))
It works great. But the problem is I run it against many worksheets and some don't have e.g. column AG,AH and end at AF at which point I get an error.
So what I need is a way to generate the string Q,R,S....[Name of Last Column in Sheet] and then I can use that instead of my hard-coded Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH but I cannot figure out how to do that.
Any help is greatly appreciated. Thanks!
Per comments above, final formula was:
LEFT("Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,A‌​L,AM,AN,AO,AP,AQ,AR,‌​AS,AT,AU,AV,AW,AX,AY‌​,AZ,BA,BB,BC ",2*Columns(INDIRECT(A2&"!1:1"))-33+IF(Columns(INDIRECT(A2&"‌​!1:1"))>26,Columns(I‌​NDIRECT(A2&"!1:1"))-‌​26,0))
where column A contains the list of worksheets (tabs) in the Google Sheet. Put this in B2, and then copied it down. I am not marking this as the correct answer since others gave a correct formula-based answer but this did the trick for me.
This can be done with built-in functions:
On a helper sheet, let say you name it, helper, fill up range with letters A to Z, let say A1:A26
Let say that on B1 you write the following formula:
=ArrayFormula({A1:A26;TRANSPOSE(SPLIT(JOIN(",",SUBSTITUTE(QUERY(TRANSPOSE(A1:A26)&A1:A26,,27)," ",",")),","))}) . This will create a list of column letter headers.
On each new worksheet use columns(1:1) to get the total number of columns.
To get your string of column headers, then you could use something like :
JOIN(",",OFFSET(helper!B1,16,0,columns(1:1)-16))
QUERY(helper!B:B,"select B limit "&columns(1:1)-7&" offset 7")
NOTE:
If you decide to have only one helper sheet and use it on several spreadsheets, then use
QUERY(IMPORTRANGE(your_url,"helper!B:B"),"select Col1 limit "&columns(1:1)-7&" offset 7")
This can be done with script. Without seeing you spreadsheet, it is hard to know exactly what you need, but this should be close. I get the variables from Sheet1 and return the formula to Sheet1. Adjust the sheet name to fit your needs. This will look at your data sheets based on the variable sheet name determine the last column. Determine the column letters and build the string the query needs. It then sets the new query formula. I added a menu to run it from.
function onOpen() {
SpreadsheetApp.getActiveSpreadsheet().addMenu(
'Create Data', [
{ name: 'Run', functionName: 'formula' },
]);
}
function formula(){
var ss= SpreadsheetApp.getActiveSpreadsheet()
var s=ss.getSheetByName("Sheet1") //sheet where variables are
var sheet=s.getRange("A2").getValue()//variable sheet name
var sel=makeString(sheet) //get the select string of column letters
//Create formula and return to Sheet1 A3
var f= s.getRange("A3").setFormula('=sum(filter(query(INDIRECT("\'" & A2 & "\'!$A$7:$23"),"select '+sel+' where B=\'"&C2&"\'",0),query(INDIRECT("\'" & A2 & "\'!$A$7:$23"),"select '+sel+' where B=\'PROJECT\'",0) >=date(2017,1,1),query(INDIRECT("\'" & A2 & "\'!$A$7:$23"),"select '+sel+' where B=\'PROJECT\'",0) <=date(2017,12,31)))')
}
function makeString(sht){
var ss= SpreadsheetApp.getActiveSpreadsheet()
var s=ss.getSheetByName(sht)
var lc=s.getLastColumn()
var rng=s.getRange(1, 17, 1, lc).getValues()
var str=''
var ltr=[]
for(var i=17;i<rng[0].length+1;i++){
ltr[i]= columnToLetter(i)
str=ltr.join(',')
}
var str1=str.substr(17)
return str1
}
function columnToLetter(column)
{
var temp, letter = '';
while (column > 0)
{
temp = (column - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column = (column - temp - 1) / 26;
}
return letter;
}
Let me know if you have any questions.

ARRAYFORMULA to SUM previous row column and current row column

https://docs.google.com/spreadsheets/d/1wlWqdFwgv90s50iP-bXXBHciyualohj610qFiSatcmQ/edit?usp=sharing
Shared the above sheet with example. I want an arrayformula to sum the previous rows column and current row column.
In F2 I entered this formula:
=ArrayFormula(if(row(B2:B)=2, B2, if(len(B2:B)+len(C2:C), mmult(transpose(if(transpose(row(B2:C))>=row(B2:C),if(B2:B<>"", B2:B,0)+(if(C2:C<>"", C2:C,0)*-1), 0)),row(B2:B)^0),)))
But.. in order for this formula to work you will have to write your 'starting' balance in B2. See also the spreadsheet you shared.
I hope that helps ?
Try doing it via Script.
function calcBalance(range,InitialBalance){
var total = [];
total[0] = InitialBalance;
for (var i=2;i<range.length;i++) {
if (range[i][0] !== "") {
total[i-1] = range[i][0]-range[i][1]+total[i-2];
}
}
total = total.slice(1);
return (total);
}
In cell D3 type
=calcBalance(B:C,D2)
Hope this helps

Resources