Dynamic if statement in Google script - arrays

I have the function below which sets values in an array to "" if each value in the row is identical and then removes the blank values from the array
If I have
arr = [[[a],[a]],[[a],[b]],[[a],[c]],[[b],[a]],[[b],[b]],[[b],[c]],[[c],[a]],[[c],[b]],[[c],[c]]]
I end up with
[[[[a],[b]],[[a],[c]],[[b],[a]],[[b],[c]],[[c],[a]],[[c],[b]]]]
But what if my array has n dimensions instead of just two
I can't figure out how to write this part dynamically
for (var i = 0; i < values.length; i++) {
if (values[i][0] == values[i][1]) {
values[i][0] = '';
values[i][1] = '';
}
}
So that the if statement was testing
values[i][0] == values[i][1]... ==values[i][n]
Thanks
My Function
function removeEmptyRng(shtName, rng, outputRng) {
var sht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(shtName);
var lr = sht.getLastRow();
var range = sht.getRange(rng + lr);
var values = range.getValues();
for (var i = 0; i < values.length; i++) {
if (values[i][0] == values[i][1]) {
values[i][0] = '';
values[i][1] = '';
}
}
//Remove Empty values
values = values.filter(function(a) {return a.filter(Boolean).length > 0;});
if (outputRng == true)
{sht.getRange(1,2,values.length,values[0].length).setValues(values)};
return values
}

You could immediately filter for the inequality in the whole row... Basically saying "keep a row if one of its values is unequal to the first of the row" => not all are equal.
values = values.filter(
function(row) {
return row.some(
function(val) {
return val != row[0]});
});

Related

How can I use a script to delete all data on a google spreadsheet?

I have a google form that exports all of the answers to a google sheet. I also have a script that exports my google sheets (aka my form answers) and converts it to json. The problem is, If I make another response on google forms, my script converts both responses into a json when I only want the most recent response to converted. What I need is an addition to my script to delete all rows after it exports the data so when I try again it doesn't take the old responses.
// Tweak the makePrettyJSON_ function to customize what kind of JSON to export.
var FORMAT_ONELINE = 'One-line';
var FORMAT_MULTILINE = 'Multi-line';
var FORMAT_PRETTY = 'Pretty';
var LANGUAGE_JS = 'JavaScript';
var LANGUAGE_PYTHON = 'Python';
var STRUCTURE_LIST = 'List';
var STRUCTURE_HASH = 'Hash (keyed by "id" column)';
/* Defaults for this particular spreadsheet, change as desired */
var DEFAULT_FORMAT = FORMAT_PRETTY;
var DEFAULT_LANGUAGE = LANGUAGE_JS;
var DEFAULT_STRUCTURE = STRUCTURE_LIST;
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [
{name: "Export JSON for this sheet", functionName: "exportSheet"},
{name: "Export JSON for all sheets", functionName: "exportAllSheets"}
];
ss.addMenu("Export JSON", menuEntries);
}
function makeLabel(app, text, id) {
var lb = app.createLabel(text);
if (id) lb.setId(id);
return lb;
}
function makeListBox(app, name, items) {
var listBox = app.createListBox().setId(name).setName(name);
listBox.setVisibleItemCount(1);
var cache = CacheService.getPublicCache();
var selectedValue = cache.get(name);
Logger.log(selectedValue);
for (var i = 0; i < items.length; i++) {
listBox.addItem(items[i]);
if (items[1] == selectedValue) {
listBox.setSelectedIndex(i);
}
}
return listBox;
}
function makeButton(app, parent, name, callback) {
var button = app.createButton(name);
app.add(button);
var handler = app.createServerClickHandler(callback).addCallbackElement(parent);;
button.addClickHandler(handler);
return button;
}
function makeTextBox(app, name) {
var textArea = app.createTextArea().setWidth('100%').setHeight('200px').setId(name).setName(name);
return textArea;
}
function exportAllSheets(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheetsData = {};
for (var i = 0; i < sheets.length; i++) {
var sheet = sheets[i];
var rowsData = getRowsData_(sheet, getExportOptions(e));
var sheetName = sheet.getName();
sheetsData[sheetName] = rowsData;
}
var json = makeJSON_(sheetsData, getExportOptions(e));
displayText_(json);
}
function exportSheet(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var rowsData = getRowsData_(sheet, getExportOptions(e));
var json = makeJSON_(rowsData, getExportOptions(e));
displayText_(json);
}
function getExportOptions(e) {
var options = {};
options.language = e && e.parameter.language || DEFAULT_LANGUAGE;
options.format = e && e.parameter.format || DEFAULT_FORMAT;
options.structure = e && e.parameter.structure || DEFAULT_STRUCTURE;
var cache = CacheService.getPublicCache();
cache.put('language', options.language);
cache.put('format', options.format);
cache.put('structure', options.structure);
Logger.log(options);
return options;
}
function makeJSON_(object, options) {
if (options.format == FORMAT_PRETTY) {
var jsonString = JSON.stringify(object, null, 4);
} else if (options.format == FORMAT_MULTILINE) {
var jsonString = Utilities.jsonStringify(object);
jsonString = jsonString.replace(/},/gi, '},\n');
jsonString = prettyJSON.replace(/":\[{"/gi, '":\n[{"');
jsonString = prettyJSON.replace(/}\],/gi, '}],\n');
} else {
var jsonString = Utilities.jsonStringify(object);
}
if (options.language == LANGUAGE_PYTHON) {
// add unicode markers
jsonString = jsonString.replace(/"([a-zA-Z]*)":\s+"/gi, '"$1": u"');
}
return jsonString;
}
function displayText_(text) {
var output = HtmlService.createHtmlOutput("<textarea style='width:100%;' rows='20'>" + text + "</textarea>");
output.setWidth(400)
output.setHeight(300);
SpreadsheetApp.getUi()
.showModalDialog(output, 'Exported JSON');
}
// getRowsData iterates row by row in the input range and returns an array of objects.
// Each object contains all the data for a given row, indexed by its normalized column name.
// Arguments:
// - sheet: the sheet object that contains the data to be processed
// - range: the exact range of cells where the data is stored
// - columnHeadersRowIndex: specifies the row number where the column names are stored.
// This argument is optional and it defaults to the row immediately above range;
// Returns an Array of objects.
function getRowsData_(sheet, options) {
var headersRange = sheet.getRange(1, 1, sheet.getFrozenRows(), sheet.getMaxColumns());
var headers = headersRange.getValues()[0];
var dataRange = sheet.getRange(sheet.getFrozenRows()+1, 1, sheet.getMaxRows(), sheet.getMaxColumns());
var objects = getObjects_(dataRange.getValues(), normalizeHeaders_(headers));
if (options.structure == STRUCTURE_HASH) {
var objectsById = {};
objects.forEach(function(object) {
objectsById[object.id] = object;
});
return objectsById;
} else {
return objects;
}
}
// getColumnsData iterates column by column in the input range and returns an array of objects.
// Each object contains all the data for a given column, indexed by its normalized row name.
// Arguments:
// - sheet: the sheet object that contains the data to be processed
// - range: the exact range of cells where the data is stored
// - rowHeadersColumnIndex: specifies the column number where the row names are stored.
// This argument is optional and it defaults to the column immediately left of the range;
// Returns an Array of objects.
function getColumnsData_(sheet, range, rowHeadersColumnIndex) {
rowHeadersColumnIndex = rowHeadersColumnIndex || range.getColumnIndex() - 1;
var headersTmp = sheet.getRange(range.getRow(), rowHeadersColumnIndex, range.getNumRows(), 1).getValues();
var headers = normalizeHeaders_(arrayTranspose_(headersTmp)[0]);
return getObjects(arrayTranspose_(range.getValues()), headers);
}
// For every row of data in data, generates an object that contains the data. Names of
// object fields are defined in keys.
// Arguments:
// - data: JavaScript 2d array
// - keys: Array of Strings that define the property names for the objects to create
function getObjects_(data, keys) {
var objects = [];
for (var i = 0; i < data.length; ++i) {
var object = {};
var hasData = false;
for (var j = 0; j < data[i].length; ++j) {
var cellData = data[i][j];
if (isCellEmpty_(cellData)) {
continue;
}
object[keys[j]] = cellData;
hasData = true;
}
if (hasData) {
objects.push(object);
}
}
return objects;
}
// Returns an Array of normalized Strings.
// Arguments:
// - headers: Array of Strings to normalize
function normalizeHeaders_(headers) {
var keys = [];
for (var i = 0; i < headers.length; ++i) {
var key = normalizeHeader_(headers[i]);
if (key.length > 0) {
keys.push(key);
}
}
return keys;
}
// Normalizes a string, by removing all alphanumeric characters and using mixed case
// to separate words. The output will always start with a lower case letter.
// This function is designed to produce JavaScript object property names.
// Arguments:
// - header: string to normalize
// Examples:
// "First Name" -> "firstName"
// "Market Cap (millions) -> "marketCapMillions
// "1 number at the beginning is ignored" -> "numberAtTheBeginningIsIgnored"
function normalizeHeader_(header) {
var key = "";
var upperCase = false;
for (var i = 0; i < header.length; ++i) {
var letter = header[i];
if (letter == " " && key.length > 0) {
upperCase = true;
continue;
}
if (!isAlnum_(letter)) {
continue;
}
if (key.length == 0 && isDigit_(letter)) {
continue; // first character must be a letter
}
if (upperCase) {
upperCase = false;
key += letter.toUpperCase();
} else {
key += letter.toLowerCase();
}
}
return key;
}
// Returns true if the cell where cellData was read from is empty.
// Arguments:
// - cellData: string
function isCellEmpty_(cellData) {
return typeof(cellData) == "string" && cellData == "";
}
// Returns true if the character char is alphabetical, false otherwise.
function isAlnum_(char) {
return char >= 'A' && char <= 'Z' ||
char >= 'a' && char <= 'z' ||
isDigit_(char);
}
// Returns true if the character char is a digit, false otherwise.
function isDigit_(char) {
return char >= '0' && char <= '9';
}
// Given a JavaScript 2d Array, this function returns the transposed table.
// Arguments:
// - data: JavaScript 2d Array
// Returns a JavaScript 2d Array
// Example: arrayTranspose([[1,2,3],[4,5,6]]) returns [[1,4],[2,5],[3,6]].
function arrayTranspose_(data) {
if (data.length == 0 || data[0].length == 0) {
return null;
}
var ret = [];
for (var i = 0; i < data[0].length; ++i) {
ret.push([]);
}
for (var i = 0; i < data.length; ++i) {
for (var j = 0; j < data[i].length; ++j) {
ret[j][i] = data[i][j];
}
}
return ret;
} ```
This isn't my original script and I am not that knowledgeable in this space so any help is appreciated.
Clear contents on all sheets
function clearAll() {
SpreadsheetApp.getActive().getSheets().forEach(sh => sh.clear());
}

How to set in Google Sheets an x time-efficient in all rows that contain a value according to getValues for example?

In the cells of the D column there is the following formula to get the actual row number (non-hidden rows): =if(subtotal(103,A?),row(),"").
function x() {
var s = SpreadsheetApp.getActive().getActiveSheet();
var values = s.getRange('D2:D').getValues();
var index = 0;
var value = values[index];
var condition = /\S/.test(value); // printable char
var ranges = [];
for (values; ?; index++) { // until the last index
if (condition) {
ranges.push('C'+value);
}
}
s.getRangeList(ranges).setValue('x');
}
A for-loop should have 3 optional expressions: intialization(var index = 0), condition (index < values.length)and final-expression(index++).
The variables that change(value and condition) in the loop should be inside the for-loop
function x() {
var s = SpreadsheetApp.getActive().getActiveSheet();
var values = s.getRange('D2:D').getValues();
var ranges = [];
for (var index = 0; index < values.length; index++) { // until the last index
var value = values[index];
var condition = /\S/.test(value); // printable char
if (condition) {
ranges.push('C'+value);
}
}
s.getRangeList(ranges).setValue('x');
}

Searching for a value and if a value exists adding a row with copying the data in google spreadsheet

I want to search for a word in a certain column and then if the value exists, I want to copy the row below with its values and change the word to two different words.
My issue was in getting the found word row Number to insert a row below it.
function myFunction() {
var ss = SpreadsheetApp.openById("1fE404JUbw3aytlqtoht6FfrIhYhTpSe2MM5UDnBkFc4");
var sheet = ss.getSheets()[0]
let range = sheet.getDataRange();
var values = range.getValues();
var typeRange = sheet.getRange("E2:E");
var typeValues = typeRange.getValues();
var i;
for(i = 0; i <= lastRow ; i++){
for (let type of typeValues){
if (type == "Both"){
var bothRow = i+1;
}
//// var bothRow = sheet.getRange(i+1,1,1,typeValues[i].length);
//// ss.insertRowsAfter(bothRow, 1);
}
}
}
I have used alert to check and it inserted an infinite number of rows after row number 1.
function myFunction() {
let sheetui= SpreadsheetApp.getUi()
sheetui.createMenu("Rahaf Game")
.addItem("Stage 1", 'pop')
.addToUi();
// var ss = SpreadsheetApp.openById("1fE404JUbw3aytlqtoht6FfrIhYhTpSe2MM5UDnBkFc4");
// var sheet = ss.getSheets()[0]
// let range = sheet.getDataRange();
// var values = range.getValues();
// var typeRange = sheet.getRange("E2:E");
// var typeValues = typeRange.getValues();
}
function pop(){
//var ss = SpreadsheetApp.openById("1fE404JUbw3aytlqtoht6FfrIhYhTpSe2MM5UDnBkFc4");
var sheet = ss.getSheets()[0]
var typeRange = sheet.getRange("E2:E");
var typeValues = typeRange.getValues();
var lastRow = sheet.getLastRow();
var i;
for(i = 0; i <= lastRow ; i++){
for (let type of typeValues){
if (type == "Both"){
var bothRow = i+1;
ss.insertRowsAfter(bothRow, 1);
}
//// var bothRow = sheet.getRange(i+1,1,1,typeValues[i].length);
//// ss.insertRowsAfter(bothRow, 1);
}
}
}
Can someone please help in achieving the required result in inserting a row below and copy the values into it with changing the word into two words?
Answer:
.getValues() returns a 2D array of values and you are referencing it as if it is unidimentional.
Code fix:
You need to change your conditional such that the object you are checking is an array:
if (type == "Both"){
//code
}
Should be:
if (type == ["Both"]){
//code
}
Adding a row and copying the data to it:
You can add a row in a sheet after a given row with the insertRowsAfter() and use .getRange().setValues() to copy in the data:
for(var i = 0; i <= lastRow ; i++){
for (let type of typeValues){
if (type == ["Both"]){
var bothRow = i + 1;
ss.insertRowsAfter(bothRow, 1);
// increment lastRow as there is now one more row in the sheet
lastRow++;
// increment i as you want to skip the row you just copied!
i++;
var rangeToCopy = sheet.getRange(bothRow + ':' + bothRow).getValues();
sheet.getRange((bothRow + 1) + ':' + (bothRow + 1)).setValues(rangeToCopy);
}
}
}
Don't forget to increment lastRow by 1 if you add a new row so that your loop still reaches the end of the sheet.
References:
Class Range | Apps Script - Method getValues()
Related Questions:
Using Google Sheets scripts, why does my if statement always return false when comparing cell values?

Reset checkboxes to false

I have a Google spreadsheet where column A has checkboxes in each row. I have written a script to perform a function on all rows where the checkboxes are checked, but I want to add in at the end a reset function so that all checked boxes are unchecked again after the script is run.
I've tried using a for loop like this:
var dataRange = sheet.getRange('A3:A');
var values = dataRange.getValues();
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[i].length; j++) {
if (values[i][j] == true) {
values[i].setValue(false);
}
}
}
But clearly this doesn't work as I get an error.
Does anyone know how this could be done?
How about this modification? I think that there are several solutions for your situation. So please think of this as one of them.
Modification points :
The reason of the issue is values[i].setValue(false);. values[i] is an array. Please use the range for setValue().
But to use setValue() in the for loop leads to higher cost. So in this modification, I used setValues().
Put "false" to values, if values[i][j] is "true".
Put the modified values to the sheet using setValues().
Modified script :
var dataRange = sheet.getRange('A3:A');
var values = dataRange.getValues();
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[i].length; j++) {
if (values[i][j] == true) {
values[i][j] = false; // Modified
}
}
}
dataRange.setValues(values); // Added
Reference :
setValue()
setValues()
If this was not what you want, please tell me. I would like to modify it.
Update:
You can now use range.uncheck() directly on the range
Alternatively, Since you want to uncheck everything in the range (and all of the range have checkboxes in them), just do:
sheet.getRange('A3:A').setValue(false);
without checking/looping.
By highlighting all the cells in the range that you want to "uncheck" hold Crtl and double tap the spacebar.
The remove-check-marks method is "uncheck"…
var range = SpreadsheetApp.getActive().getRange('A21:A59');
range.uncheck();
This solution posted above does reset all checkboxes;
however, it also unexpectedly changes cells with the value of 1 in it to FALSE.
I want to make a script to reset checkboxes on ALL sheets...
function resetCheckBoxesAllSheets() {
var ss = SpreadsheetApp.getActive();
var allsheets = ss.getSheets();
for (var s in allsheets){
var sheet=allsheets[s]
var dataRange = sheet.getRange('A4:Z100');
var values = dataRange.getValues();
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[i].length; j++) {
if (values[i][j] == true) {
values[i][j] = false; // Modified
}
}
}
dataRange.setValues(values);
}//end of sheets loop.
}// end of function...
I have set one checkbox instead of caption as shown in the picture
I write a script for check the data range and check uncheck all accordingly.
Here is the script.
function onEdit(e){
Logger.log('OnEdit');
var range = e.range;
var cl = range.getColumn();
var rw = range.getRow();
Logger.log('Row = ' + rw + ' Column = ' + cl);
var ActiveSheet = ss.getActiveSheet();
if(ActiveSheet.getName() === 'Companies' && rw == 1 && cl == 5){
var isAllTrue = ActiveSheet.getRange(rw, cl).getValue();
if(isAllTrue == true){
var Avals = ActiveSheet.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
ActiveSheet.getRange(2, 5, Number(Alast-1)).setValue(true);
}
else
{
var Avals = ActiveSheet.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
ActiveSheet.getRange(2, 5, Number(Alast-1)).setValue(false);
}
}
}
Change sheet name as per your need.
Note: create onedit trigger for same function if not trigger auto.

Google Script array value undefined

i wrote a code that should take a value from a cell and than convert it to the string and than into the array. its working fine. I can see the value of arr in Logs as an array with the input of the cell. For example, in the cell are " dog, cat " and tha arr value in Logs is [dog, cat].
But after i create this array, i would like to make a loop on it. And than i become in Logs, that arr is undefined. Can somebody help me please? im working on it for 2 days :(
Here is my code:
function animal (s,z){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var range = sheet.getRange("SM");
var columnNumber = getColumnNumberOfSM(s);
var rowNumber = getRowNumberOfSM(z);
var colAction = columnNumber + 1;
var action = sheet.getRange(rowNumber, colAction, 1, 1).getValues();
var bar = action.toString();
var arr = [{}];
arr = bar.split(", ");
//return arr; // returns an array [dog, cat]
var foo = arr; // underfined
for (var i = 0; i <= foo.length; ++i) {
if (foo[i] == "dog") {
Logger.log(upload());
}
}
}
now i edit my code and its working fine,but only with "dog" but not with "cat"
function animal(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var action = sheet.getRange("C3").getValue();
var bar = action.toString();
var arr = bar.split(", ");
for (var i = 0; i <= arr.length; ++i) {
if (arr[i] == "dog") { // works
Logger.log(upload());
}
if (arr[i] == "cat") { // doesn't work
Logger.log(upload());
}
}
}
You don't need to initiate arr as blank you can directly initialize it as a result to split method , also one point I didn't get is why do you need to assign arr to foo? You can directly iterate through arr.length and perform the required operation.
Here's my working snippet.
var parts = path.split(",");
for (var i = 0; i < parts.length; i++) {
if (parts[i] == 'dog'){
Logger.log(parts[i]);
}
}

Resources