How to build multi-dimensional arrays in the appropriate orientation. (Rows/Cols in correct places) - arrays

I'm working on building a Google Sheets-based tool to calculate the cost of making various machined and fabricated parts. As it currently sits, there are about 60 different variables that I modify each time I build an estimate. Things like "number of parts," "length of bar to cut each part from," "cost/bar," "machining time," "machining rate," etc. All of these values I have populated on one sheet, and laid out in a way like. I want to make a button that takes a "snapshot" of all of these values, and stores them on another sheet for later reference. I'd then, ideally create another button, that allows me to re-populate all of the cells based off of a unique ID (such as Part #). This would let me tweak an estimate, or even refer back to material sizes etc in a meaningful way.
So far, I've created a "Named Range" for each of the values, so that as I change the layout, or add values, my script code should update accordingly, instead of using direct cell references.
I've built a few functions to get and set the value's of these named ranges. They're working as expected(i think) for what I'm trying to do. But when I try to place the array of Named Ranges inside of a multi-dimensional array of the named ranges WITH their respective values, I'm running into an issue where each named range is a ROW and their respective value is a second Column. And I need it swapped
I'm not super comfortable with multi-dimensional arrays and am thinking myself in circles trying to figure out how to transpose this logically. My gut says the way I'm attempting to build the arrays is my problem, not just how I'm iterating through them.
function saveCurrentValues(){
//set master spreadhseet
var ss = SpreadsheetApp.getActiveSpreadsheet();
//set calc and save sheets to vars
var calcSheet = ss.getSheetByName('Part Cost Calculator')
var saveSheet = ss.getSheetByName('Saved Parts');
//set named ranges from calcSheet to array
var namedRanges = calcSheet.getNamedRanges();
var savedValues = new Array();
//find next available row for save data (currently troubleshooting)
var nextAvailSaveRange = saveSheet.getRange(1, 1, 60, 2);
//iterate through array and call getNamedRange() function to return name and current value
for(i = 0; i < namedRanges.length; i++){
savedValues[i] = getNamedRange(namedRanges[i].getName());
}
nextAvailSaveRange.setValues(savedValues);
}
function getNamedRange(name){
var ss = SpreadsheetApp.getActiveSheet();
var value = ss.getRange(name).getValue();
Logger.log([name,value]);
return [name, value];
}
As you can see by how I had to temporarily format the nextAvailSaveRange, it needs 60 ROWS, and only two columns, because of how the array is constructed. I'd like to better understand how I'm creating this multi-dimensional array vertically instead of horizontally, and how to fix it!
Once this is done, I'd like to create headers that match the Named Ranges on my save sheet, to allow me to iterate through functions and look for a match to the appropriate column by name. That way if I add more values or change their order, or the order of the array, it wont matter. I think I'll be able to figure that out pretty easily if I can control these damn arrays better!

I agree with the OP. Array building AND iteration are the immediate problems and they are the stumbling block to the development of the spreadsheet.
The OP has a raised number of issues, however the most immediate, and the one to be resolved under this answer, is the copying of a list of parts from one sheet to another. In the OP's code, named ranges were retrieved and used as a basis for creating the copy of the list of parts. However, this also creates a duplicate set of named ranges on the target sheet. In my view this was unnecessarily complicating the duplication of the parts list since it is easy to programmatically create/update a list of named ranges.
The following code consists of three functions:
so_5466573501() - Copies the list of parts from one sheet to another.
Named Ranges are ignored; the OP's stumbling block is the iteration of the raw data and management of arrays. This code deals only with that aspect as a means of simplifying this issue.
createnamedranges() - Programmatically creates/updates Named ranges.
This code is included to assure the OP that it is not important to make named ranges the focus of the duplication by showing how easy it is to programmatically turn a list of parts into a series of Named Ranges (for development, I created 60 Parts and the entire code executes in under a 1 second). The code assumes a list in two columns (Column A = Parameter Name, Column B = Parameter value). The code loops through the list creating/updating a set of named ranges - the range name is the Parameter Name in Column A, and the range itself is the the corresponding row in Column B. The name of the sheet is set in a variable, so this function can be easily adapted.
deletenamedranges() - Programmatically deletes Named ranges.
This code deletes all the Named Ranges from a given sheet. This function is included because the OP's existing code creates duplicate named ranges, and it might be necessary to quickly delete them from a sheet. The sheet name is stored as a variable, so the function can be easily adapted.
function so_5466573501() {
//set master spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
//create variables for calc and save sheets
var calcSheet = ss.getSheetByName('Part Cost Calculator')
var saveSheet = ss.getSheetByName('Saved Parts');
//get the Parts Parameters from Part Cost Calculator
//var namedRanges = calcSheet.getNamedRanges();
//Logger.log("DEBUG: Number of named ranges on Parts Cost Calculator = "+namedRanges.length);
// get the number of parts in the list on Parts Cost Calculator
var Avals = calcSheet.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
//Logger.log("DEBUG: Number of parts in the list: "+Alast); //DEBUG
// get the parts list
var partsRange = calcSheet.getRange(1, 1, Alast, 2);
var partsRangeValues = partsRange.getValues();
//Logger.log("DEBUG: The parts range is: "+partsRange.getA1Notation());//DEBUG
//Logger.log("DEBUG: Parts List Row #1: Name: "+partsRangeValues[0][0]+", Value: "+partsRangeValues[0][1]);//DEBUG
// create an array to use for saving results and updating new Saved Parts sheet
var savedValues = new Array();
// Loop through the Parts List, row by row
for (i = 0; i < Alast; i++) {
// push the part name and part value onto the array
savedValues.push([partsRangeValues[i][0], partsRangeValues[i][1]]);
//Logger.log("DEBUG: Parts List: i = "+i+", Name: "+partsRangeValues[i][0]+", Value: "+partsRangeValues[i][1]);//DEBUG
}
// identify the range on the Saved Parts sheet to copy the parts list array.
var saveRange = saveSheet.getRange(1, 1, Alast, 2);
saveRange.setValues(savedValues);
}
function createnamedranges() {
//set master spreadhseet
var ss = SpreadsheetApp.getActiveSpreadsheet();
//create variables for calc and save sheets
var calcSheetName = "Part Cost Calculator";
var calcSheet = ss.getSheetByName(calcSheetName);
// get the number of parts in the list on Parts Cost Calculator
var AVals = calcSheet.getRange("A1:A").getValues();
var ALast = AVals.filter(String).length;
// get the parts range and values
var partsRange = calcSheet.getRange(1, 1, ALast, 2);
//Logger.log("DEBUG: The Parts range is "+partsRange.getA1Notation());//DEBUG
var partsRangeValues = partsRange.getValues();
// Loop through the parts list row by row
for (var i = 0; i < ALast; i++) {
// get the Part name and assign as the range name
var nrpartname = partsRangeValues[i][0];
//Logger.log("DEBUG: PartName = "+nrpartname+", value: "+partsRangeValues[i][1]);//DEBUG
// get the range to be named -note (i+1) because the loop starts at 0 (zero) but `getrange` starts at 1 (one)
var rng_to_name = ss.getSheetByName(calcSheetName).getRange((i + 1), 2);
//Logger.log("DEBUG: rng_to_name: "+rng_to_name+", range details: "+rng_to_name.getA1Notation());
// set (and/or update) the named range
ss.setNamedRange(nrpartname, rng_to_name);
// DEBUG: check that the range was created //DEBUG
// var rangeCheck = ss.getRangeByName(nrpartname);//DEBUG
// var rangeCheckName = rangeCheck.getA1Notation(); //DEBUG
// Logger.log("DEBUG: Rangename: "+nrpartname+", Range: "+rangeCheckName);//DEBUG
// credit megabyte1024 https://stackoverflow.com/a/12325103/1330560 "setNamedRange() outside of the spreadsheet container?"
}
}
function deletenamedranges() {
//set master spreadhseet
var ss = SpreadsheetApp.getActiveSpreadsheet();
//create variables for calc and save sheets
var calcSheet = ss.getSheetByName('Part Cost Calculator');
// get the named ranges
var namedRanges = calcSheet.getNamedRanges();
// loop through the list of named ranges and delete them
for (var i = 0; i < namedRanges.length; i++) {
namedRanges[i].remove();
}
}
ADDENDUM: - Copy based on Named Ranges
The original so_5466573501 assumes that the parts are in a simple 2 column-list; in which case, Named Ranges are irrelevant.
The following code assumes that the parts are not in a list but scattered, in no particular order, throughout the sheet "Part Cost Calculator". This code is based on obtaining the NamedRanges, identifying the respective Named Range row and column, correlating said row and column to the ENTIRE data range, and then copying the results to the "Saved Parts" sheet. No Named Ranges are created by default on the "Saved Parts" sheet but this can be easily done by using the createnamedranges function (appropriately edited for the correct sheet name).
function so_5466573502() {
//set master spreadhseet
var ss = SpreadsheetApp.getActiveSpreadsheet();
//create variables for calc and save sheets
var calcSheet = ss.getSheetByName('Part Cost Calculator')
var saveSheet = ss.getSheetByName('Saved Parts');
//get the Parts Parameters from Part Cost Calculator
var namedRanges = calcSheet.getNamedRanges();
var numNR = namedRanges.length
//Logger.log("DEBUG: Number of named ranges on Parts Cost Calculator = "+numNR);
// get all the data
var dataRangeValues = calcSheet.getDataRange().getValues();
// create an array to temporarily store results
var resultsarray = [];
// Loop through the array of Named Ranges
for (var x = 0; x < numNR; x++) {
var nrName = namedRanges[x].getName();
var nrRange = namedRanges[x].getRange();
var nrRangerow = nrRange.getRow();
var nrRangecol = nrRange.getColumn();
var nrRangeValue = dataRangeValues[nrRangerow - 1][nrRangecol - 1];
//Logger.log("DEBUG: Named Range-Name: "+nrName+", Range: "+nrRange.getA1Notation()+", Row: "+nrRangerow+", Column: "+nrRangecol+", Value-"+nrRangeValue);//DEBUG
// populate the array with the part name and the part value
resultsarray.push([nrName, nrRangeValue]);
}
// identify the range on the Saved Parts sheet to copy the parts list array.
var saveRange = saveSheet.getRange(1, 1, numNR, 2);
saveRange.setValues(resultsarray);
// sort the results on "Saved Parts"
saveRange.activate().sort({
column: 1,
ascending: true
});
}

Related

Google Apps Script: how to create an array of values for a given value by reading from a two column list?

I have a set of data in a Google spreadsheet in two columns. One column is a list of article titles and the other is the ID of a hotel that is in that article. Call it list1.
Example data
I would like returned a new list with article titles in one column, and an array of the hotel IDs in that article in the other column. Call it list2.
Example data
There are thousands of lines that this needs to be done for, and so my hope was to use Google Apps Script to help perform this task. My original thinking was to
Create column 1 of list2 which has the unique article titles (no script here, just the G-sheets =unique() formula.
Iterate through the titles in list2, looking for a match in first column of the list1
If there is a match:
retrieve its corresponding value in column 2
push it to an empty array in column two of list2
move onto next row in list1
if no longer a match, loop back to step 2.
I've written the following code. I am currently getting a type error (TypeError: Cannot read property '0' of undefined (line 13, file "Code")), however, I wanted to ask whether this is even a valid approach to the problem?
function getHotelIds() {
var outputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('list2');
var lastRow = outputSheet.getLastRow();
var data = outputSheet.getRange(2,1,lastRow,2).getValues();
var workingSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('list1');
var lastActiveRow = workingSheet.getLastRow();
var itemIDS = [];
for (var i=1; i<=data.length; i++) {
var currentArticle = data[i][0];
var lookupArticle = workingSheet[i][0];
if (currentArticle === lookupArticle) {
var tempValue = [workingSheet[i][1]];
itemIDS.push(tempValue);
}
}
}
Use a simple google sheets formula:
You can use a very simple formula to achieve your goal instead of using long and complicated scripts.
Use =unique(list1!A2:A) in cell A2 of list2 sheet to get the unique hotels.
and then use this formula to all the unique hotels by dragging it down in column B.
=JOIN(",",filter(list1!B:B,list1!A:A=A2))
You got the idea right, but the logic needed some tweaking. The "undefined" error is caused by the workingSheet[i][0]. WorkingSheet is a Sheet object, not an array of data. Also, is not necessary to get the data from list2 (output), it is rather the opposite. You have to get the data from the list1 (source) sheet instead, and iterate over it.
I added a new variable, oldHotel, which will be used to compare each line with the current hotel. If it's different, it means we have reached a different Hotel and the data should be written in list2.
function getHotelIds() {
var outputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('list2');
var outLastRow = outputSheet.getLastRow();
var workingSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('list1');
var lastActiveRow = workingSheet.getLastRow();
var sourceValues = workingSheet.getRange("A2:B" + lastActiveRow).getValues();
var itemIDS = [];
var oldHotel = sourceValues[0][0]; //first hotel of the list
for (var i = 0; i < sourceValues.length; i++) {
if (sourceValues[i][0] == oldHotel) {
itemIDS.push(sourceValues[i][1]);
/*When we reach the end of the list, the oldHotel variable will never be different. So the next if condition is needed. Otherwise it wouldn't write down the last Hotel.
*/
if (i == sourceValues.length - 1) {
outputSheet.getRange(outLastRow + 1, 1, 1, 2).setValues([
[sourceValues[i][0], itemIDS.toString()]
]);
}
} else {
outputSheet.getRange(outLastRow + 1, 1, 1, 2).setValues([
[sourceValues[i - 1][0], itemIDS.toString()]
]);
oldHotel = sourceValues[i][0]; //new Hotel will be compared
outLastRow = outputSheet.getLastRow(); //lastrow has updated
itemIDS = []; //clears the array to include the next codes
}
}
}
I also converted the itemIDS array to a String each time, so it's written down in a single cell without issues.
Make sure each column of the Sheet is set to "Plain text" from Format > Number > Plain Text
References
getRange
setValues
toString()

Comparing multiple values in Google Sheets with App Script for loops

I would like to compare multiple values in a Google Sheet spreadsheet some using for loops in Google App Script. But i would like some advice on the best way to do it.
To explain below...
I have two spreadsheets, A "FOOD" table, and A "FOOD GROUP" table. 
I've written a for loop script that goes through the entire FOOD table.
If the key value of both tables matches, the script will update a column from the FOOD table with a column from the FOOD GROUP table.
The script works without issues. But it can only compare one column between the 2 tables at a time. I would like to modify this script so I can compare multiple columns at once, without having to create a for loop for each specified column.
I pasted my code below. I can also provide images of my spreadsheet if you need it. 
In any case, I'm new to coding, so any constructive feedback or insight to improve my script will be helpful. I'm happy to answer any questions if anything seems unclear.
function FoodGroup_Test() {
var Data = SpreadsheetApp.getActiveSpreadsheet();
var FoodGroupDataSheet = Data.getSheetByName("Food Groups") // "FoodGroup" sheet
var FoodGroupAllValues = FoodGroupDataSheet.getRange(2, 1, FoodGroupDataSheet.getLastRow()-1,FoodGroupDataSheet.getLastColumn()).getValues();
var FoodGroupDataLastRow = FoodGroupDataSheet.getLastRow();
var FoodDataSheet = Data.getSheetByName("Food") // "Food" sheet
var FoodAllValues = FoodDataSheet.getRange(2, 1, FoodDataSheet.getLastRow()-1,FoodDataSheet.getLastColumn()).getValues();
// Object to contain all FoodGroup column values
var Object = {};
for(var FO = FoodGroupAllValues.length-1;FO>=0;FO--) // for each row in the "FoodGroup" sheet...
{
Object[FoodGroupAllValues[FO][15]] = FoodGroupAllValues[FO][11]; // ...store FoodGroup ID Key value
}
for(var F = FoodAllValues.length-1;F>=0;F--) // for each row in the "Food" sheet...
{
var Food_FoodGroupKey = FoodAllValues[F][94]; // Store FoodGroup Key value.
// ...if the Food value dont match, update it with FoodGroup's value
if (Object[Food_FoodGroupKey] != FoodAllValues[F][95])
{
FoodAllValues[F][95] = Object[Food_FoodGroupKey];
}
}
// declare range to place updated values, then set it.
var FoodDestinationRange = FoodDataSheet.getRange(2, 1, FoodAllValues.length, FoodAllValues[0].length);
FoodDestinationRange.setValues(FoodAllValues);
}
FOOD GROUP Table
FOOD table
In order for your code to work as expected, you should do the following changes to your code:
Update your if condition to this one:
Object[Food_FoodGroupKey] != FoodAllValues[F][95] && object2[] != FAllValues[F][86])
In order to avoid the undefined problem use the following line of code:
FoodDataSheet.createTextFinder("undefined").replaceAllWith("");

AppScript: 'number of columns in the data does not match the number of columns in the range.' setValues method not reading array correctly?

I'm trying to automate the collection of phone numbers from an API into a Google Sheet with app script. I can get the data and place it in an array with the following code:
const options = {
method: 'GET',
headers: {
Authorization: 'Bearer XXXXXXXXXXXXXXX',
Accept: 'Application/JSON',
}
};
var serviceUrl = "dummyurl.com/?params";
var data=UrlFetchApp.fetch(serviceUrl, options);
if(data.getResponseCode() == 200) {
var response = JSON.parse(data.getContentText());
if (response !== null){
var keys = Object.keys(response.call).length;
var phoneArray = [];
for(i = 0; i < keys; i++) {
phoneArray.push(response.call[i].caller.caller_id);
}
This works as expected - it grabs yesterday's caller ID values from a particular marketing campaign from my API. Next, I want to import this data into a column in my spreadsheet. To do this, I use the setValues method like so:
Logger.log(phoneArray);
var arrayWrapper = [];
arrayWrapper.push(phoneArray);
Logger.log(arrayWrapper);
for(i = 0; i < keys; i++) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var cell = sheet.getRange("A8");
cell.setValues(arrayWrapper);
}
}
}
}
I am aware that I need my array length to equal the length of the selected range of cells in my sheet. However, I get conflicting errors depending on the length I set for my getRange method. If I set it to a single cell, as you see above, the error I get is:
The number of columns in the data does not match the number of columns in the range. The data has 8 but the range has 1.
However, if I set the length of my range to 8 (or any value except 1), I get the error:
The number of columns in the data does not match the number of columns in the range. The data has 1 but the range has 8.
As you see, the error swaps values. Now I have the appropriate number of columns in the range, but my script only finds 1 cell of data. When I check the log, I see that my 2D array looks normal in both cases - 8 phone numbers in an array wrapped in another array.
What is causing this error? I cannot find reference to similar errors on SO or elsewhere.
Also, please note that I'm aware this code is a little wonky (weird variables and two for loops where one would do). I've been troubleshooting this for a couple hours and was originally using setValue instead of setValues. While trying to debug it, things got split up and moved around a lot.
The dimension of your range is one row and several columns
If you push an array into another array, the dimension will be [[...],[...],[...]] - i.e. you have one column and multiple rows
What you want instead is one row and multiple columns: [[...,...,...]]
To achieve this you need to create a two-dimensional array and push all entries into the first row of your array: phoneArray[0]=[]; phoneArray[0].push(...);
Sample:
var phoneArray = [];
phoneArray[0]=[];
for(i = 0; i < keys; i++) {
var phoneNumber = response.call[i].caller.caller_id;
phoneNumber = phoneNumber.replace(/-/g,'');
phoneArray[0].push(phoneNumber);
}
var range = sheet.getRange(1,8,1, keys);
range.setValues(phoneArray);
So I figured out how to make this work, though I can't speak to why the error is occurring, or rather why one receives reversed error messages depending on the setRange value.
Rather than pushing the whole list of values from the API to phoneArray, I structured my first for loop to reset the value of phoneArray each loop and push a single value array to my arrayWrapper, like so:
for(i = 0; i < keys; i++) {
var phoneArray = [];
var phoneNumber = response.call[i].caller.caller_id;
phoneNumber = phoneNumber.replace(/-/g,'');
phoneArray.push(phoneNumber);
arrayWrapper.push(phoneArray);
}
Note that I also edited the formatting of the phone numbers to suit my needs, so I pulled each value into a variable to make replacing a character simple. What this new for loop results in is a 2D array like so:
[[1235556789],[0987776543],[0009872345]]
Rather than what I had before, which was like this:
[[1235556789,0987776543,0009872345]]
It would appear that this is how the setValues method wants its data structured, although the documentation suggests otherwise.
Regardless, if anyone were to run into similar issues, this is the gist of what must be done to fix it, or at least the method I found worked. I'm sure there are far more performant and elegant solutions than mine, but I will be dealing with dozens of rows of data, not thousands or millions. Performance isn't a big concern for me.
var correct = [[data],[data]] -
is the data structure that is required for setValues()
therefore
?.setValues(correct)

In a form, I need to populate the contents of same spreadsheet column like 50 times. Is there a way to script this logic with fewer iterations

I'm working on a form where I need to pull the contents of a spreadsheet column like 50 times, to try to input multiple items from a list. I see that I can do this by defining a few variables and redoing a small piece of Script again and again. I want to see if anyone can help me overcome this lengthy script to make it smaller with fewer iterations. Thanks.
function updateForm(){
// call the form and connect to the drop-down items
var Form_SQ = FormApp.openById("FORM ID");
var SQ_IT01_List = Form_SQ.getItemById("ITEM 01").asListItem();
var SQ_IT02_List = Form_SQ.getItemById("ITEM 02").asListItem();
//Similarly defining upto 50 dropdown lists.
var SS01 = SpreadsheetApp.getActive();
var SQ_IT01_Names = SS01.getSheetByName("Sheet2");
var SQ_IT02_Names = SS01.getSheetByName("Sheet2");
//Similarly defining upto 50 names lists.
// Item_01 Part Number Dropdown
var SQ_IT01_Values = SQ_IT01_Names.getRange(2, 1, SQ_IT01_Names.getMaxRows() - 1).getValues();
var SQ_IT01_Items = [];
for(var i = 0; i < SQ_IT01_Values.length; i++)
if(SQ_IT01_Values[i][0] != "")
SQ_IT01_Items[i] = SQ_IT01_Values[i][0];
SQ_IT01_List.setChoiceValues(SQ_IT01_Items);
// Item_02 Part Number Dropdown
var SQ_IT02_Values = SQ_IT01_Names.getRange(2, 1, SQ_IT02_Names.getMaxRows() - 1).getValues();
var SQ_IT02_Items = [];
for(var i = 0; i < SQ_IT02_Values.length; i++)
if(SQ_IT02_Values[i][0] != "")
SQ_IT02_Items[i] = SQ_IT02_Values[i][0];
SQ_IT02_List.setChoiceValues(SQ_IT02_Items);
//Similarly defining upto 50 lookup lists.
}
Problem
Reusing code and making use of loops. Scripting is all about efficiency (see DRY principle): make as little assignments and same-functionality coding as possible - use loops, move reusable code snippets to functions that can be called on demand, etc.
Solution
This sample makes several assumptions:
SQ_IT01_Names is different for each item (in your sample it always is Sheet2 - if this is the case, you don't have to reassign it 50 times, one variable assignment will do just fine).
You intended to do something when a value is an empty string (the sample just filters them out). As you use the [index] notation, those values in the resulting Array will be undefined (and that's not something one would want in an Array of choice values).
All items are choice items (if you need id filtering, the sample is easily expanded).
function updateForm() {
var form = FormApp.openById("FORM ID");
//access every item;
var items = form.getItems();
var ss = SpreadsheetApp.getActive();
//loop over items;
items.forEach(function(item,i){
var namesSheet = ss.getSheetByName('Sheet'+i); //assuming this is diff each time;
var namesRange = namesSheet.getRange(2,1,namesSheet.getLastRow());
var namesValues = namesRange.getValues();
//map values to first column;
namesValues = namesValues.map(function(value){
return value[0];
});
//filter out undefined (undefined and false functional equivalence);
namesValues = namesValues.filter(function(value){
return value;
});
item.asListItem().setChoiceValues(namesValues);
});
}
Notes
Please, use closures {} with loops and if statements, this way you'll be able to keep track of which statements are enclosed in it and save yourself debugging time when looping / conditioning multiple statements.
Since you only need rows that have data in them, use the getLastRow() method instead of the getMaxRows()-1 calc you have to perform in your script.
Reference
forEach() method reference;
filter() method reference;
map() method reference;
getLastRow() method reference;

Google Apps Script Replace and update cell within a range

I have a Google spreadsheet that I'm trying to remove the word "woo" within a range of cells
So far I've managed to loop through the results and log the results, however I haven't figured how to update that information in the spreadsheet itself.
Any guidance would be welcomed
Thank you
function myFunction () {
var ss = SpreadsheetApp.getActiveSheet().getRange('B:B')
var data = ss.getValues();
for (var i = 0; i < data.length; i++) {
var text = data[i].toString();
var finaltext = text.replace(/woo/g, "");
data[i] = finaltext;
Logger.log(data[i]);
}
}
Use setValues()
Notes:
Usually ss is used as a shorthand for spreadsheet, as it's used on the code for a range it's better to use range as a variable name.
setValues() returns a 2D array, so data[i] returns an array of row values rather than a cell value. To get/set cell values, use data[i][0] notation.
Considering the above replace
var ss = SpreadsheetApp.getActiveSheet().getRange('B:B')
by
var range = SpreadsheetApp.getActiveSheet().getRange('B:B')
then add the following line after the for block.
range.setValues(data);
Regarding text var declaration, replace
var text = data[i].toString();
to
var text = data[i][0].toString();
Using open ended references like B:B could lead to problems. To avoid them be sure to keep the sheet rows at minimum or better instead of using an open ended reference use something like B1:B10.

Resources