Setting the setActiveSelection where there is zero - google-apps-script

I have a tremendous volume of sparse matrix data, where i want to programmatically set as active cell wherever there is (0) when I run the below snippet (function).
Which would ease me for manipulation of code labels
The data is purely random. The process has to begin from the current active cell and it has to loop again from beginning if end of the data is found.
I get unexpected results,
function getzero() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var Values = range.getValues();
for (var i = 0; i < Values.length; i++) {
for (var j = 0; j < Values[i].length; j++) {
if (Values[i][j] == 0) {
sheet.setActiveSelection(sheet.getRange(i + 1, j + 1));
break;
}
}
}
}

This should take care of finding all the zeros. Also added a menu for you to run the command from the sheets directly. Just paste code in the script editor and reload the sheet.
// This function addes a menu Zero and submenu getzero to access your function directly from spreadsheet
function onOpen(){
var ss = SpreadsheetApp.getActive()
var menu = [{name:"Find Zero",functionName: "getzero"}]
ss.addMenu("Zeroes", menu)
}
function getzero() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var Values = range.getValues();
var selectedRange = sheet.getActiveRange()
// find active cells row and column
var startRow = selectedRange.getRow() -1
var startCol = selectedRange.getColumn()
var notFoundZero = true
//Use the active cells row and column to start the loop
for (var i = startRow; i < Values.length; i++) {
if (i == startRow){
var j = startCol
}
else {
j =0
}
for (j ; j < Values[i].length; j++) {
// Using "===" makes sure the type is also match else blank is considered as zero too.
if (Values[i][j] === 0) {
Logger.log("Values Row X Col:" + i + " X " + j)
//The below line works as well as sheet.setActiveSelection
sheet.getRange(i + 1, j + 1).activate()
//Below code escapes the outer loop
i = Values.length;
// this boolean is used to runs or stops the next loop
notFoundZero = false;
// breaks inner loop
break;
}
}
}
if(notFoundZero){
for (var i = 0; i <= startRow; i++) {
if (i == startRow){
var runTill = startCol
}
else {
runTill = Values[i].length
}
for (var j=0 ; j < runTill; j++) {
if (Values[i][j] === 0) {
sheet.getRange(i + 1, j + 1).activate()
// same as above
i = Values.length;
//Used to alert if no more zeros found
notFoundZero = false;
break;
}
}
}
}
if(notFoundZero)
{
var ui = SpreadsheetApp.getUi()
ui.alert("No More zero Found")
}
}
This will check cell values after selection if no zeroes are found it will check above the selection. But after that it will stop at the selection and alert no zeroes found, this prevents a runaway loop.
Give it a go and let me know how it goes.
Edit: Below Code for searching in reverse
Below Code Has not been Tested, Might have errors. This was not the primary Question, hence did not check for errors.
function getzeroRev() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var Values = range.getValues();
var selectedRange = sheet.getActiveRange()
// find active cells row and column
var startRow = selectedRange.getRow() -1
var startCol = selectedRange.getColumn()
var notFoundZero = true
//Use the active cells row and column to start the loop
for (var i = startRow; i >=0; i--) {
if (i == startRow){
var j = startCol
}
else {
j =values[i].length
}
for (j ; j >=0; j--) {
// Using "===" makes sure the type is also match else blank is considered as zero too.
if (Values[i][j] === 0) {
Logger.log("Values Row X Col:" + i + " X " + j)
//The below line works as well as sheet.setActiveSelection
sheet.getRange(i + 1, j + 1).activate()
//Below code escapes the outer loop
i = Values.length;
// this boolean is used to runs or stops the next loop
notFoundZero = false;
// breaks inner loop
break;
}
}
}
if(notFoundZero){
for (var i = values.length; i >= startRow; i--) {
if (i == startRow){
var runTill = startCol
}
else {
runTill = 0
}
for (var j=0 ; j >= runTill; j--) {
if (Values[i][j] === 0) {
sheet.getRange(i + 1, j + 1).activate()
// same as above
i = Values.length;
//Used to alert if no more zeros found
notFoundZero = false;
break;
}
}
}
}
if(notFoundZero)
{
var ui = SpreadsheetApp.getUi()
ui.alert("No More zero Found")
}
}

Related

Cell reference is out of range - But I use GetDataRange()

I've tried a bunch of solution but it always end with Cell ref is out of range.
I thought that GetDataRange() & GetLastRow() would cover the last non-blank cell but I'm stuck. I've tried to hardcode my cell values (from X to Y) but nothing seems to change.
var course;
var searchingCol;
function CalculateFurnitureList()
{
GetCourseString();
FindColumnNumber(course);
GetSpecialFurnituresValue();
}
function GetCourseString()
{
var activeSheet = SpreadsheetApp.getActiveSheet();
var courseType = activeSheet.getRange("A2").getValue();
Browser.msgBox('Generate furniture list for ' + courseType + ' course');
course = courseType;
}
function FindColumnNumber(ct)
{
var furnitureSheet = SpreadsheetApp.getActive().getSheetByName("MaterielCours");
var range = furnitureSheet.getDataRange();
var width = range.getWidth();
//Search every cell in the designated area to find the course name
for (var i = 1; i <= width; i++)
{
var data = range.getCell(1,i);
if (data.getValue() == ct)
{
Browser.msgBox('Trouvé ! ' + data.getValue() + ' se trouve en : ' + i +':1');
searchingCol = i;
}
}
}
function GetSpecialFurnituresValue()
{
Browser.msgBox(searchingCol);
var furnitureSheet = SpreadsheetApp.getActive().getSheetByName("MaterielCours");
var range = furnitureSheet.getDataRange();
var length = range.getLastRow();
for (var i = 1; i < length; i++)
{
var data = range.getCell(searchingCol, i);
if (data.getValue() !== "")
{
// Do nothing
}
else
{
if (data == "Abs")
{
Browser.msgBox('NTM');
}
else
{
// Calculate value
}
}
}
}
It's
var data = range.getCell(searchingCol, i);
in GetSpecialFurnituresValue() which causes the problem.
The weird thing is that the same process in FindColumnNumber is working perfectly.
(editing my original answer - I must have been tired!) In the function GetSpecialFurnitureValues, there are a few things.
The for loop uses i < length, but it should be <= or you will miss the last row:
// for (var i = 1; i < length; i++)
for (var i = 1; i <= length; i++)
Your column/rows were simply reversed. :)
// var data = range.getCell(searchingCol, i);
var data = range.getCell(i, searchingCol);
Hope that helps!

Set Value of checkbox

I want to uncheck a checkbox if an adjacent cell has a value input in it.
function onEdit(event) {
var eventRange = event.range;
if (eventRange.getColumn() == 3) { // 3 == column C
var columnFRange = SpreadsheetApp.getActiveSheet().getRange(eventRange.getRow(), 6, eventRange.getNumRows(), 6);
var values = columnFRange.getValues();
for (var i = 0; i < values.length; i++) {
values[i][0] = 'FALSE';
}
columnFRange.setValues(values);
}
}
This looks at a sheet called "Testing" and if there is a value in column A it will put "TRUE" in the adjacent cell to the right. I believe this is what you're going for?
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Testing");
var hasValue = sheet.getRange("A:A").getValues();
var value = '';
for(var i = 0; i < hasValue.length; i++){
if(hasValue[i][0].length > 0) {
sheet.getRange("B" + (i + 1)).setValue("TRUE");
}
else {
sheet.getRange("B" + (i + 1)).setValue("");
}
}
}

infinite loading in google spreadsheet in function script

i use function script in google spread sheet.
this function is used maybe... 150,000 cell.
my question is... infinite loading.
when i use my custom function in sheet, infinite loading appear
how can i resolve that?
here is my script code :
function s2hex(str1){
var s2hex = 0;
var byte_check = 0;
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("tbl");
var range1 = sheet1.getRange(1, 1, sheet1.getMaxRows(),
sheet1.getMaxColumns());
for(var i = 0; i < str1.length; ++i){
for(var k = 1; k < sheet1.getMaxRows(); ++k){
if(str1[i] == range1.getCell(k, 2).getValue() || str1[i] == " "){
s2hex = s2hex + 1;
byte_check = 1;
break;
}
}
if(byte_check == 0){
s2hex = s2hex + 2;
}
byte_check = 0;
}
return s2hex;
};
getMaxRows() will return all rows in the sheet. If you have content in A1:A10 and there are empty rows from A10 to A100000. It'll return 100,000 instead of 10. Use getLastRow() instead.
If you're only using the second column,Specify 2 as column number and 1 instead of getMaxColumns()
Use getValues() to get a single array instead of making multiple calls to spreadsheet.
Try Modifying from:
var range1 = sheet1.getRange(1, 1, sheet1.getMaxRows(), sheet1.getMaxColumns());
for(var i = 0; i < str1.length; ++i)
{
for(var k = 1; k < sheet1.getMaxRows(); ++k)
{
if(str1[i] == range1.getCell(k, 2).getValue() || str1[i] == " ")
{
s2hex = s2hex + 1;
To
var lr =sheet1.getLastRow(); //One last row call to be used in multiple places
var range = sheet1.getRange(1, 2, lr,1);
var range1 = range.getValues(); //get all values in a single call
for(var i = 0; i < str1.length; ++i)
{
for(var k = 0; k < lr; ++k) //k to 0.Array index start at 0
{
if(str1[i] == range1[k][0] || str1[i] == " ") //Check the 2D value of already retrieved array
{
s2hex = s2hex + 1;
150,000 function calls will slow down any sheet.
That said, your function is in dire need of optimization: you need to remove the need for extensive calls over the Spreadsheet interface. Each such call can take as much as 0.1 second. You can do this simply, by reading the entire range of your values to search with getValues(), and then iterating that in the same manner as you do currently.

How Do I Clear Any Cells That Have Certain Text Strings?

I have a spreadsheet that is receiving Google Form responses. I'd like to run something on formSubmit() that combs through the entire form response sheet, and clears any cells that have certain values in the text string.
The code I have so far is below. It run, but doesn't clear the cells out.
function badData() {
var file = SpreadsheetApp.openById("[spreadsheetstring]");
var content = file.getSheetByName("Form Responses 1");
return content.value ? (listBadWords(content.value) !== -1 ? content.range.clearContent() : null) : null;
}
function listBadWords(word) {
var listEN = [
'none', 'n/a', 'n.a'
];
return listEN.indexOf(word);
}
Any help/advice you all could provide would be greatly appreciated.
Thanks!
Update:
With #Liora's help, the following works great:
function badMMData() {
var file = SpreadsheetApp.openById("[spreadsheetstring]");
var content = file.getSheetByName("Form Responses 1");
var numRows = content.getLastRow();
var numCols = content.getLastColumn();
var range = content.getRange(1, 1, numRows, numCols);
for (var i = 1; i <= numRows; i++) {
for (var j = 1; j <= numCols; j++) {
var currentValue = range.getCell(i, j).getValue().toString().toLowerCase();
if (listBadWords(currentValue) !== -1)
range.getCell(i, j).clear();
}
}
}
function listBadWords(word) {
var listEN = [
'none', 'n/a', 'n.a', 'na'
];
return listEN.indexOf(word);
}
The function clear works on a precise range, so you need to loop on all the ranges of the spreadsheet. Something like:
var numRows = content.getLastRow();
var numCols = content.getLastColumns();
var range = content.getRange(1, 1, numRows, numCols);
for (var i = 1; i <= numRows; i++) {
for (var j = 1; j <= numCols; j++) {
var currentValue = range.getCell(i,j).getValue();
if(listBadWords(currentValue) !== -1)
range.getCell(i,j).clear();
}
}

SpreadsheetApp.getActiveSpreadsheet() returning null

I need a quick function to loop through the rows of one of my sheets so I constructed this:
function getTotalsOf(name, type) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(name);
var data = sheet.getDataRange().getValues();
var total = 0.00;
for (var i = 0; i < data.length; i++) {
if (data[i][0]== "") break;
if (data[i][2] == type) {
var temp = (Number(data[i][4]) + Number(data[i][5]) + Number(data[i][6])) * data [i][3];
total = Number(total) + total;
}
}
return total;
}
SpreadsheetApp.getActiveSpreadsheet() seems to return null when I try to execute the function. It also returns null when I try to get the spreadsheet by id. Am I missing something?
EDIT:
I retried using my spreadsheet id (https://docs.google.com/spreadsheets/d/STRINGFROMHERE/edit#gid=1235572150) with the same results.
function getTotalsOf(name, type) {
var sheet = SpreadsheetApp.openById("**STRINGFROMURL**").getSheetByName(name);
var data = sheet.getDataRange().getValues();
var total = 0.00;
for (var i = 0; i < data.length; i++) {
if (data[i][0]== "") break;
if (data[i][2] == type) {
var temp = (Number(data[i][4]) + Number(data[i][5]) + Number(data[i][6])) * data [i][3];
total = Number(total) + temp;
}
}
return total;
}
I think you just missed a few concepts with regard to looping through spreadsheets. Hope this demo will help and get you what you want. Always remember that rows and cols in spreadsheets starts with 1,1 not 0,0.
function loopThroughCells() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = sheet.getDataRange().getValues();
Logger.log(data[0].length);
for(var i=0; i< data.length; i++){
for(var j=0; j<data[i].length; j++){
if(data[i][j] == "HELIOS"){
if (data[i][j]== "") break;
Logger.log("HELIOS data found in range "+ (i+1) + " "+(j+1));
}
}
}
Log
[17-07-07 21:45:17:157 HKT] HELIOS data found in range 3 3