Average of Numbers in Column If Condition In Different Column Satisfied - javascript

I have a data range of which the first column are dates and the second column are numerical values. There are some rows where the second column value is blank and I do not want them to be counted.
I am trying to find the average of the second column values if they satisfy the criteria of being within 3 months ago from today (blank values should not be counted).
But I am stuck as I cannot even get the total correct. And I do not know how to proceed further to get the average.
The code belows seem to give me appended strings instead of summing up the numbers mathematically.
Can anyone help please?
Thanks in advance.
function average() {
// open spreadsheet
var spreadsheet = SpreadsheetApp.openById("spreadsheetID");
// set the named sheet as active
var sheet = SpreadsheetApp.setActiveSheet(spreadsheet.getSheetByName("SheetName"));
// figure out what the last row is
var lastRow = spreadsheet.getSheetByName("Form responses 1").getLastRow();
// the rows are indexed starting at 1, and the first row is the headers, so start with row 2
var startRow = 2;
// get the data range
var responsesValues = spreadsheet.getSheetByName("Form responses 1").getRange("A1:Q" + lastRow).getValues();
// define the dates
var timeToday = new Date().getTime();
var dateToday = new Date().getDate();
var date = new Date();
var threeMonthsAgo = new Date(date.getFullYear(), date.getMonth() - 3, 0);
// grab column 1 (date of entry column) (second variable in getRange function below)
var dataRange = sheet.getRange(2,1,lastRow-startRow+1,1 );
var numRows = dataRange.getNumRows();
var dateOfEntryValues = dataRange.getValues();
// grab column 2 (values to be averaged)
range = sheet.getRange(2, 2, lastRow-startRow+1, 1);
var Values = range.getValues();
var warning_count = 0;
var sumValues = 0;
// Loop over the values
for (var i = 0; i <= numRows - 1; i++) {
var dateOfEntry = dateOfEntryValues[i][0];
if(dateOfEntry > threeMonthsAgo && dateOfEntry !== "") {
// if it's within 3 months ago, add the values.
sumValues += Values[i][0];
warning_count++;
}
}

There is a lot more simple version. Just put into the Destination Cell the formula
=ArrayFormula(AVERAGE(IF(DATEDIF(C1:C;TODAY();"D")<=90;E1:E)))
replacing C1:C with the column with dates and E1:E with the column with numbers.

Related

Google sheet script auto add new rows with copied formulas

I need to create function which adds rows with copied formulas from above rows. After the script is launched it should result in accurate number (set 5 i this code) of blank rows at the end of the sheet.
The code I managed to create counts what number of rows should be added but adds only one row with copied formulas at the end.
Please help me edit this code to multiple the result of the function by "rowstoadd" parameter.
Sheet image
function autoaddRows() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Harmonogram');
var range = sheet.getRange("B2:B").getValues();
var lastRowB = range.filter(String).length + 2;
var lastRowA = sheet.getLastRow();
var blanknrows = sheet.getLastRow() - lastRowB;
if (blanknrows < 5) {
let rowstoadd = 5 - blanknrows;
Browser.msgBox(rowstoadd);
let spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
let lastRowIndex = sheet.getLastRow();
let existingRange = getRowRange(sheet, lastRowIndex);
sheet.insertRowAfter(lastRowIndex);
let newRange = getRowRange(sheet, ++lastRowIndex);
existingRange.copyTo(newRange);
newRange.setFormulas(newRange.getFormulas());
newRange.clearNote();
}
function getRowRange(sheet, rowIndex) {
return sheet.getRange(rowIndex, 1, 1, sheet.getLastColumn());
}
}
I believe your goal is as follows.
You want to keep 5 new empty rows.
For example, when the last row of column "A" is 10 and the last row of column "B" is 9, you want to add 4 new rows.
Also, you want to put the formula to the column "B" of the inserted rows.
In this case, how about the following modified script?
Modified script:
function autoaddRows() {
var addRows = 5;
var sheet = SpreadsheetApp.getActive().getSheetByName('Harmonogram');
var range = sheet.getRange("B2:B").getValues();
var lastRowB = range.filter(String).length + 1;
var lastRow = sheet.getLastRow();
var blanknrows = lastRow - lastRowB;
var diff = addRows - blanknrows;
if (diff > 0) {
sheet.insertRowsAfter(lastRow, diff);
// var range = sheet.getRange("B" + lastRowB);
// range.copyTo(range.offset(1, 0, diff + 1), SpreadsheetApp.CopyPasteType.PASTE_FORMULA, false);
var numberOfCol = sheet.getLastColumn() - 1;
var range = sheet.getRange(lastRowB, 2, 1, numberOfCol);
range.copyTo(range.offset(1, 0, diff + 1, numberOfCol), SpreadsheetApp.CopyPasteType.PASTE_FORMULA, false);
range.clearNote();
}
}
In this modification, the difference between the last rows between column "A" and column "B" is retrieved. And the empty rows are inserted using the difference.
In your script, newRange.clearNote(); is used. So, I also add range.clearNote();. If you want to remove it, please remove it.
References:
insertRowsAfter(afterPosition, howMany)
copyTo(destination, copyPasteType, transposed)

hideColumns() number of columns parameter based on referenced column index Google Apps Script Google Sheets

I am trying to do hideColumns() in google sheets. The starting column is always fixed (column B) but the number of columns to hide is variable depending on a date function. Each cell in the header row has a date, and I want to hide all columns with a date before today's date. So I did a lookup and found the index number of the column with today's date and I want to simply reference that index minus 1 to come up with the number of columns to hide.
The below will work if I hard code a value for number of columns (e.g. 3) but it won't work if I reference i or even try to redefine i as a variable
function onOpen(e) {
// Get column index of yesterday's date
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName('Daily Tracker');
var lastColumn = sheet.getLastColumn();
var data = sheet.getRange(1,2,1,lastColumn).getDisplayValues().flat(); //create an array of data from row 1
for (var i = 0; i <= data.length; i++) {
var dateToday = Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy")
if (data[i] == dateToday)
{
return i;
break;
}
var hiddenColumnCount = i - 1;
// Number of columns to hide = index - 1 (e.g. 10/14/2020 = index of 8. I need to hide columns 10/6/2020 through 10/13/2020, which = 7 columns so i - 1)
// Hide all columns from column B through column with yesterday's date
sheet.hideColumns(2,hiddenColumnCount);
}
}
I don't know if i is unable to be referenced because maybe it's a string and not a number since I flattened the array from above. But I tried converting to a number using parseInt() but not sure if it worked or if it's the right thing. I've also tried defining var hiddenColumnCount = 0 above the for statement and then instead of return i I tried typing hiddenColumnCount = i - 1 but this didn't work either
I'm new to programming and try to look everything up on my own but I've hit a road block
I believe your goal as follows.
From Each cell in the header row has a date, and I want to hide all columns with a date before today's date. and I want to simply reference that index minus 1 to come up with the number of columns to hide., in your situation, when the date of today can be found, you want to hide the columns "B" to the left side of the column with the date.
Modifcation points:
In your case, it seems that the column number of the date of today can be retrieved. I think that this can be used for achieving your goal.
When the array of data is looped, please modify the condition of for loop from for (var i = 0; i <= data.length; i++) { to for (var i = 0; i < data.length; i++) {. When i <= data.length is used, the last loop is the index of out of array.
In your script, when the date of today is found, the script is finished.
When hideColumns is used, I think that in your case, this can be put to the out of for loop.
When above points are reflected to your script, it becomes as follows.
Modified script:
function onOpen(e) {
// Get column index of yesterday's date
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName('Daily Tracker');
var lastColumn = sheet.getLastColumn();
var data = sheet.getRange(1,2,1,lastColumn).getDisplayValues().flat(); //create an array of data from row 1
// I modified below script.
var columnNumber = 0;
for (var i = 0; i < data.length; i++) {
var dateToday = Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy");
if (data[i] == dateToday) {
columnNumber = i + 2;
}
}
sheet.hideColumns(2, columnNumber - 2);
// Here, columnNumber is the column number of the found date.
}
Note:
In this modification, it supposes that the date is the ascending order from the column "B". Please be careful this. When above modified script is not the result you expect, I think that it might be required to confirm the situation of Spreadsheet.
Reference:
hideColumns(columnIndex, numColumns)
Try this:
function onOpen(e) {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Daily Tracker');
var data = sheet.getRange(1,2,1,sh.getLastColumn()).getDisplayValues().flat();
for(var i = 0; i <= data.length; i++) {
if (data[i]==Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy")){break;}else{sh.hideColumn(i+2);}
}
}

Google Sheets - Moving row to another sheet based on specific column

Very new to the Google Sheets script editing, but I'm trying to move rows between sheets. I've done this successfully using getLastRow however now I'm attempting to do this based on a specific column. The reason for this is that the sheet the info is heading to has preset data validation fields and checkboxes, resulting in the row going to row 1000 every time.
I'm looking for when an option is selected on the dropdown menu on the current sheet, it will find the first free row based on a certain column, and replace that row (which is essentially empty except for the preset fields).
Currently I have as follows:
function onEdit(event) {
// Move rows to different sheets based on action selected
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = SpreadsheetApp.getActiveRange();
if(range.getColumn() == 5 && range.getValue() == "Active") {
var row = range.getRow();
var numColumns = sheet.getLastColumn();
var targetSheet = spreadsheet.getSheetByName("Active");
var target = targetSheet.getRange(targetSheet.getLastRowSpecial(8) + 1, 1);
sheet.getRange(row, 1, 1, numColumns).moveTo(target);
sheet.deleteRow(row);
and I found the below and other examples when googling but nothing seems to work:
function getLastRowSpecial(column){
// Get the last row with data for the whole sheet.
var numRows = targetSheet.getLastRow();
// Get all data for the given column
var data = targetSheet.getRange(1, column, numRows).getValues();
// Iterate backwards and find first non empty cell
for(var i = data.length - 1 ; i >= 0 ; i--){
if (data[i][0] != null && data[i][0] != ""){
return i + 1;
}
}
}
Any help is greatly appreciated!
function onEdit(e) {
//Logger.log(JSON.stringify(e));
//e.source.toast(e.range.columnStart, e.value)
var sh=e.range.getSheet();
if(e.range.columnStart==8 && e.value=="Active") {
var tsh=e.source.getSheetByName("Active");
var target=tsh.getRange(getColumnHeight(8,tsh,e.source) + 1, 1);
sh.getRange(e.range.rowStart,1,1,sh.getLastColumn()).moveTo(target);
sh.deleteRow(e.range.rowStart);
}
}
function getColumnHeight(col,sh,ss){
var ss=ss||SpreadsheetApp.getActive();
var sh=sh||ss.getActiveSheet();
var col=col||sh.getActiveCell().getColumn();
var s=0;
var h=0;
if(sh.getLastRow()) {
var v=sh.getRange(1,col,sh.getLastRow(),1).getValues().map(function(r){return r[0];});
v.forEach(function(e,i){if(e==''){s++;}else{s=0;}h++;});
}
return (h-s);
}

Trigger email alert based on last row's condition NOT WORKING

I attempted to build a script but there are some issues. The table format are 2 columns which are date and values. These are the needs:
IDEAL STATE
Grab the last filled row (today's date) in the Google Sheets called "test".
Check in that row if the value in column F is greater than 0.5.
If it greater than 0.5, then trigger an email.
In email body, it should state "Results found on [date]."
This was my starting point but it does not produce what I want. These are the issues:
CURRENT STATE
1.The script grabs every row in which column F was greater than 0.5 in the past. I only want to check for today (which would be the last row). It should not look through everything in the past.
2.The email body states: Result found on [row number]". This makes no sense. I want the date to show, not the row number.
This is the current code. Please help.
function readCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("test");
var values = sheet.getRange("F3:F").getValues(); //this has the values
var date = sheet.getRange("D3:D").getValues(); // this has the date
var results = [];
for(var i=0;i<values.length;i++){
if(values[i]>=0.5)
{
results.push("Result found on:" +(i+3));
}
}
MailApp.sendEmail('blabla#gmail.com', 'Alert', results.join("\n"));
};
Last Row in this context is Row 217, not 218, assuming sheet.getLastRow() would ignore #DIV/o! values. See screenshot for this.
LATEST UPDATE
The current Error is related "toDateString". I think it may be related that my Google Sheet is one day behind. So, it today is Jan 10, the last row in my Google Sheet is Jan 9th. I think that is why the error happens. Can you confirm? In that case, how do I change it to today-1 day?
See below.
Here's how you can check the last row:
function readCell() {
var sheet = SpreadsheetApp.getActive().getSheetByName('test');
var lastRow = sheet.getLastRow();
var value = sheet.getRange('F' + lastRow).getValue();
var date = sheet.getRange('D' + lastRow).getValue();
if (value >= 0.5) {
var result = 'Result found on: ' + date;
MailApp.sendEmail('blabla#gmail.com', 'Alert', result);
}
};
After seeing your data, I think the code below would suit you better.
function readCell() {
var sheet = SpreadsheetApp.getActive().getSheetByName('test');
var dates = sheet.getRange('D1:D').getValues();
var date = null;
var dateRow = 0;
var dateCount = dates.length;
var yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
var yesterdayString = yesterday.toDateString();
for (dateRow; dateRow < dateCount; ++dateCount) {
date = dates[dateRow];
if (date instanceof Date) {
date = date.toDateString();
if (date === yesterdayString) {
++dateRow;
// To account for zero-based array
break;
}
}
}
var value = sheet.getRange('F' + dateRow).getValue();
if (value >= 0.5) {
var result = 'Result found on: ' + date;
MailApp.sendEmail('blabla#gmail.com', 'Alert', result);
}
};

calculating with dates and for loop

I am trying to make a for loop with dates but it isn't going as planned.
What I am trying to do is input startdate in cell A1 and enddate in cell B1.
Then a for loop which runs: if startdate is less then enddate, put date in cell A2 and proceed to next column. The only thing I am stuck with is how to add one day to a date.
See code below:
function test()
{
var app = SpreadsheetApp;
var ss = app.getActive();
var sheet = ss.getActiveSheet();
var start = sheet.getRange("A1").getValue();
var end = sheet.getRange("B1").getValue();
var day = 3600*24*1000;
var diff = Math.floor((end-start)/day);
var column = 1;
for(var i=0;i<=diff;i++)
{
sheet.getRange(2, column).setValue(start+i*day);
column++;
}
}
Can someone explain to me why it doesn't work.
Thanks a lot
Assuming start is a Date, then your issue is:
start + i * day
Where the + operator is used, the left operand (the Date) is an object so is reduced to a primitive with hint string, so the + is treated as string concatenation, not a number.
You can try:
+start + i * day
to coerce start to a number, but then the result will be a number, not a Date. Also it doesn't deal with the length of day issue. I suggest you first copy the start date so you don't modify it, then increment the copy per the duplicate:
function test() {
var app = SpreadsheetApp;
var ss = app.getActive();
var sheet = ss.getActiveSheet();
var start = sheet.getRange("A1").getValue();
start = new Date(+start);
var end = sheet.getRange("B1").getValue();
var column = 1;
for (var i=0; start <= end; i++) {
sheet.getRange(2, column++).setValue(new Date(start.setDate(start.getDate() + 1)));
}
}

Categories

Resources