Counting non empty cells with matching font color in Google Sheets - google-apps-script

I'm using a custom function to count the number of cells with a matching font color in a range.
function countIfFont(countRange,fontRef,rangeSum) {
var activeRange = SpreadsheetApp.getActiveRange();
var activeSheet = activeRange.getSheet();
var range = activeSheet.getRange(countRange);
var rangeHeight = range.getHeight();
var rangeWidth = range.getWidth();
var fc = range.getFontColors();
var fontCell = activeSheet.getRange(fontRef);
var font = fontCell.getFontColor();
var count = 0;
for(var i = 0; i < rangeHeight; i++)
for(var j = 0; j < rangeWidth; j++)
if(fc[i][j] == font)
count = count+1;
return count;
};
It works, but it is counting blank cells and I want it to exclude blank cells. How do I check if the cell is blank?

In your script, how about the following modification?
From:
for(var i = 0; i < rangeHeight; i++)
for(var j = 0; j < rangeWidth; j++)
if(fc[i][j] == font)
count = count+1;
To:
var values = range.getDisplayValues();
for (var i = 0; i < rangeHeight; i++)
for (var j = 0; j < rangeWidth; j++)
if (fc[i][j] == font && values[i][j])
count = count + 1;
By this modification, when fc[i][j] == font and the cell is not empty, count = count + 1 is run.

Related

How to count only filtered cells within a function that counts cells of a certain color

This is my function for counting colored cells within a sheet. However, I need to add another variable which counts only the cells displayed, after filtering the data.
function countColoredCells(countRange,colorRef) {
var activeRange = SpreadsheetApp.getActiveRange();
var activeSheet = SpreadsheetApp.getActiveSheet();
var activeformula = activeRange.getFormula();
var countRangeAddress = activeformula.match(/\((.*)\,/).pop().trim();
var backGrounds = activeSheet.getRange(countRangeAddress).getBackgrounds();
var colorRefAddress = activeformula.match(/\,(.*)\)/).pop().trim();
var BackGround = activeSheet.getRange(colorRefAddress).getBackground();
var countCells = 0;
for (var i = 0; i < backGrounds.length; i++)
for (var k = 0; k < backGrounds[i].length; k++)
if ( backGrounds[i][k] == BackGround )
countCells = countCells + 1;
return countCells;
};
If I filter the raw data, it still displays the count of ALL data. I then tried to nest the function within the following function:
function applyOverdueFilter() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getDataRange().getDisplayValues();
var newData= ss.filter(function countColoredCells(countRange,colorRef) {
var activeRange = SpreadsheetApp.getActiveRange();
var activeSheet = SpreadsheetApp.getActiveSheet();
var activeformula = activeRange.getFormula();
var countRangeAddress = activeformula.match(/\((.*)\,/).pop().trim();
var backGrounds = activeSheet.getRange(countRangeAddress).getBackgrounds();
var colorRefAddress = activeformula.match(/\,(.*)\)/).pop().trim();
var BackGround = activeSheet.getRange(colorRefAddress).getBackground();
var countCells = 0;
for (var i = 0; i < backGrounds.length; i++)
for (var k = 0; k < backGrounds[i].length; k++)
if ( backGrounds[i][k] == BackGround )
countCells = countCells + 1;
return countCells;
}
Any help is appreciated,

Is there a i.height parameter in appscript?

i tried to find any info on it, i want to use height of the row in a cycle, i know that there is i.length, but is it one for height?
example with length:
for (var i = 2; i <= data.length+1; ++i)
i want it to look something like:
for (var g = 1; g<=grupa.height+1;g++)
this is my whole code, if you want for some reason to look at it:
function myFunction()
{
const ss = SpreadsheetApp.openByUrl ('my url');
var sheet = ss.getSheetByName("Розклад")
var data = sheet.getRange(2, 1, sheet.getLastRow()-1 , sheet.getLastColumn()).getValues();
Logger.log(data);
for (var i = 2; i <= data.length+1; ++i)
{
var data1 = sheet.getRange(i,1,1,13).getValues()
var data2 = sheet.getRange(i,8,1,13).getValues()
var grupas = data [i-2][4]
var cell= data [i-2][8]
var grupa = ss.getSheetByName(grupas)
var grupav = grupa.getRange(1,1,grupa.getLastRow(), grupa.getLastColumn()).getValues();
for (var g = 1; g<=grupa.height+1;g++)
{
var grupap = grupa[0][g-1]
Logger.log(grupap)
}
Logger.log(grupas)
Logger.log(grupav)
Logger.log(cell)
Logger.log(data1);
if ( cell ==="")
{
Logger.log('blank cell');
}
else
{
Logger.log(data2)
}
Logger.log(i-1);
}
}
var grupa = ss.getSheetByName(grupas)
var grupav = grupa.getRange(1,1,grupa.getLastRow(), grupa.getLastColumn()).getValues();
for (var j = 0; j < grupav.length; j++) {
/* grupav[j][0] */
}
Row loop
const col = 0;
const values = sheet.getDataRange().getValues();
for (const i = 0; i < values.length; i++) {
/* values[i][col] */
}
Column loop
const row = 0;
const values = sheet.getDataRange().getValues();
for (const j = 0; j < values[0].length; j++) {
/* values[row][j] */
}
Row & Column loop
const values = sheet.getDataRange().getValues();
for (const i = 0; i < values.length; i++) {
for (const j = 0; j < values[0].length; j++) {
/* values[i][j] */
}
}

writing a count program to find the number of repeatitions

I am writing a code to count the number of times a time duration in column B is repeated.After writing a code according to my logic I am still getting error or no output. Here's the app script code I have written. Help me out.
function count() {
var data = SpreadsheetApp.getActive();
var sheet = data.getSheetByName("Sheet4");
var lastRow = sheet.getLastRow();
var sh = sheet.getRange('B1:B' + lastRow);
var cell = sh.getValues();
var count = 0;
for (var i = 0; i < lastRow; j++) {
var column2 = cell[i][1];
for (var j = 0; j < i; j++) {
var column4 = cell[j][1];
if (column4 == column2) {
count++;
}
}
sheet.getRange('F' + (i + 1).toString()).setValue(count);
}
}
This is the intended output instead of column F i put the sample output in column C
Issue(s):
Outer loop's increment variable doesn't change.
for (var i = 0; i < lastRow;/*i never changes =>*/ j++)
Date/Time are retrieved as JavaScript objects and cannot be compared with ==:
if (column4 == column2) {//Date objects cannot be compared
cell doesn't have a value at array index [1]
Solution:
Increment all variables in the for -loop
Compare value of date objects instead
Array indexes start at [0]
Snippet:
for (var i = 0; i < lastRow; ++i) {
var column2 = cell[i][0];
/*....*/
var column4 = cell[j][0];
if (column4 - column2 === 0) {//#see https://stackoverflow.com/questions/492994

Google script Execution failed: please try again later and consider using batch operations. The user is over quota

I have a script where I'm syncing my google contacts with google spreadsheet.
I have around 11000 contacts in my account and I've written a function getContacts which fetches all contact information from the google contacts and sends it to a function printContacts,how ever as there are too many contacts the script fails to execute to completion.
I tried using the code to create a trigger everytime the max execution time is reached but now I'm facing a new problem,as I have too many ContactsApi call the script is showing an error saying 'user quota exceeded'
If anyone can get this code to work,it'd be a great help
//Function gets the contacts from the Google Contacts and stores in an array. Calls printContacts function with that array and no. of rows as argument
function getContacts() {
var startTime= (new Date()).getTime();
Logger.log("start time set")
var scriptProperties = PropertiesService.getScriptProperties();
var num_contacts = scriptProperties.getProperty('num_contacts');
Logger.log("script property num_contacts : "+Number(num_contacts))
setHeader();
var groupName = 'System Group: My Contacts';
var group = ContactsApp.getContactGroup(groupName);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var contacts = ContactsApp.getContactsByGroup(group);
var allContacts = [];
var contactDetails = [];
var data, numData, dataArray = [], extraArray = [];
var contact_length = contacts.length;
Logger.log("contact_length : "+contact_length);
Logger.log("contacts.length : "+contacts.length);
var MAX_RUNNING_TIME = 300000;
var REASONALBLE_TIME_TO_WAIT = 60000;
var limit = contact_length;
Logger.log("limit :"+limit)
for(var i=Number(num_contacts); i <= contacts.length; i++) {
var currTime = (new Date()).getTime();
if(currTime - startTime >= MAX_RUNNING_TIME){
Logger.log("Value of i in if section : "+i)
scriptProperties.setProperty("num_contacts",i);
ScriptApp.newTrigger("getContacts")
.timeBased()
.at(new Date(currTime+REASONALBLE_TIME_TO_WAIT))
.create();
Logger.log("trigger created for i = "+i)
break;
}
else{
if(i < contacts.length)
{
allContacts[i] = [];
contactDetails[0] = contacts[i].getGivenName();
contactDetails[1] = contacts[i].getFamilyName();
data = contacts[i].getEmails();
numData = data.length;
for(var j = 0; j < numData; j++) {
dataArray[j] = data[j].getAddress();
}
contactDetails[2] = dataArray.join("\n");
dataArray = [];
data = contacts[i].getPhones(ContactsApp.Field.MOBILE_PHONE);
numData = data.length;
for(var j = 0; j < numData; j++) {
dataArray[j] = data[j].getPhoneNumber();
}
contactDetails[3] = dataArray.join("\n");
dataArray = [];
data = contacts[i].getPhones(ContactsApp.Field.WORK_PHONE);
numData = data.length;
for(var j = 0; j < numData; j++) {
dataArray[j] = data[j].getPhoneNumber();
}
contactDetails[5] = dataArray.join("\n");
dataArray = [];
// new section for home_phone ----- start
data = contacts[i].getPhones(ContactsApp.Field.HOME_PHONE);
numData = data.length;
for(var j = 0; j < numData; j++){
dataArray[j] = data[j].getPhoneNumber();
}
contactDetails[6] = dataArray.join("\n");
dataArray = [];
// new section for home_phone ----- end
data = contacts[i].getCompanies();
numData = data.length;
for(var j = 0; j < numData; j++) {
dataArray[j] = data[j].getCompanyName();
extraArray[j] = data[j].getJobTitle();
}
contactDetails[7] = dataArray.join("\n");
dataArray = [];
contactDetails[8] = extraArray.join("\n");
data = contacts[i].getAddresses();
numData = data.length;
for(var j = 0; j < numData; j++) {
dataArray[j] = data[j].getAddress();
}
contactDetails[9] = dataArray.join("\n");
dataArray = [];
contactDetails[10] = contacts[i].getNotes();
data = contacts[i].getCustomFields();
numData = data.length;
for(var j = 0; j < numData; j++) {
dataArray[j] = data[j].getValue();
}
contactDetails[11] = dataArray.join("\n");
dataArray = [];
data = [];
data = contacts[i].getContactGroups();
numData = data.length;
for(var j = 0; j < numData; j++) {
if(data[j].getName() == 'System Group: My Contacts')
{
continue;
}
else
{
dataArray[j] = data[j].getName();
}
}
contactDetails[4] = dataArray.join("\n");
dataArray = [];
contactDetails[12] = 'saved';
contactDetails[13] = contacts[i].getId();
for(var j = 0; j < 14; j++) {
allContacts[i][j] = contactDetails[j];
}
}
}
}
Logger.log("last value of i "+i);
Logger.log("num of contacts "+allContacts.length)
printContacts(allContacts, contacts.length);
setProperties_getContacts();
return;
}
//Function to print contacts to the spreadsheet.
function printContacts(contactsArray, i) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange(2, 1, i, 14);
range.setValues(contactsArray);
}

Losing importXML functions when running my current script

I am writing a Google script to copy values from a column of importXML data based on a certain date. Below is where I am currently, but the issue I am running into now is when the script is run it is removing the importXML formulas located in columnns G and H:
function moveValuesOnly2() {
var sheet = SpreadsheetApp.openById("0At2fAZApHI8adHJxWU5EVVBEbHd0YzA5UVBwOGQ3ZHc");
SpreadsheetApp.setActiveSpreadsheet(sheet);
SpreadsheetApp.setActiveSheet(sheet.getSheetByName('Dylan'))
var range= sheet.getRange("B3:AJ50");
var currentValue = range.getValues();
var COL_B = 0; // relative to col B
var COL_G = 5;
var COL_H = 6;
var COL_I = 7;
var COL_J = 8;
var COL_K = 9;
var COL_L = 10;
var COL_N = 12;
var COL_O = 13;
var COL_P = 14;
var COL_R = 16;
var COL_S = 17;
var COL_T = 18;
var COL_V = 20;
var COL_W = 21;
var COL_X = 22;
var COL_Z = 24;
var COL_AA = 25;
var COL_AB = 26;
var COL_AD = 28;
var COL_AE = 29;
var COL_AF = 30;
var COL_AH = 32;
var COL_AI = 33;
var COL_AJ = 34;
for(var i = 0 ; i < currentValue.length ; i++){
if (currentValue[i][0] == (1)) {
// Copy value at 0 days
currentValue[i][COL_J] = currentValue[i][COL_G];
currentValue[i][COL_K] = currentValue[i][COL_H];
currentValue[i][COL_L] = currentValue[i][COL_I];
}
for(var i = 0 ; i < currentValue.length ; i++){
if (currentValue[i][0] == (15)) {
// Copy value at 15 days
currentValue[i][COL_N] = currentValue[i][COL_G];
currentValue[i][COL_O] = currentValue[i][COL_H];
currentValue[i][COL_P] = currentValue[i][COL_I];
}
range.setValues(currentValue);
}
for(var i = 0 ; i < currentValue.length ; i++){
if (currentValue[i][0] == (30)) {
// Copy value at 30 days
currentValue[i][COL_R] = currentValue[i][COL_G];
currentValue[i][COL_S] = currentValue[i][COL_H];
currentValue[i][COL_T] = currentValue[i][COL_I];
}
range.setValues(currentValue);
}
for(var i = 0 ; i < currentValue.length ; i++){
if (currentValue[i][0] == (45)) {
// Copy value at 45 days
currentValue[i][COL_V] = currentValue[i][COL_G];
currentValue[i][COL_W] = currentValue[i][COL_H];
currentValue[i][COL_X] = currentValue[i][COL_I];
}
range.setValues(currentValue);
}
for(var i = 0 ; i < currentValue.length ; i++){
if (currentValue[i][0] == (60)) {
// Copy value at 60 days
currentValue[i][COL_Z] = currentValue[i][COL_G];
currentValue[i][COL_AA] = currentValue[i][COL_H];
currentValue[i][COL_AB] = currentValue[i][COL_I];
}
range.setValues(currentValue);
}
for(var i = 0 ; i < currentValue.length ; i++){
if (currentValue[i][0] == (75)) {
// Copy value at 75 days
currentValue[i][COL_AD] = currentValue[i][COL_G];
currentValue[i][COL_AE] = currentValue[i][COL_H];
currentValue[i][COL_AF] = currentValue[i][COL_I];
}
range.setValues(currentValue);
}
for(var i = 0 ; i < currentValue.length ; i++){
if (currentValue[i][0] == (90)) {
// Copy value at 90 days
currentValue[i][COL_AH] = currentValue[i][COL_G];
currentValue[i][COL_AI] = currentValue[i][COL_H];
currentValue[i][COL_AJ] = currentValue[i][COL_I];
}
range.setValues(currentValue);
}}}
Is there any way to prevent the ImportXML functions located in those columns from being lost each time the script is run. Also a huge thank you to user #Srik to getting to me to the point I am at!
I would think that the problem lies from the fact that you setValues on the range which includes your columns G & H.
The solution lies in using
var specialRange = sheet.getRange("G3:H50");
var formulas = specialRange.getFormulas();
at the begining of your script to save the formulas and then after your setValues call to use the following code
specialRange.setFormulas(formulas);
Let me know how that works for you.