Looping a function in Google Sheets - javascript

I am trying to migrate from Microsoft Excel to Google sheets in order for the company to work from any work station.
I want to compare two ranges of data, one in one column and the other in another column.
If the cell value in the first range equals the cell value in the second range, then I want it to...
Add the value from the second range to the first range in the matching cell and continue checking the rest of the range.
I have done this easily in VBA but I am having a hard time doing it in Goole Sheets.
For now the code in Google Sheets does the following:
If it finds a matching value between the two ranges it adds the value to the every single cell in the first range.
Here is what my code looks like:
function myFunction() {
var pr = SpreadsheetApp.openById("my spreadsheet");
var sheet = pr.getSheetByName("sheet1");
var sheet1 = pr.getSheetByName("sheet1");
var cell = sheet.getRange('J3:J95');
var cell1 = sheet1.getRange('C3:C1125');
if(cell1.getValue()===cell.getValue()) {
cell1.offset(0, 2).setValue(cell1.offset(0, 2).getValue() + cell.offset(0, 1).getValue())
}
}
How can I make this add value only to the one matching cell and not the entire range?

You can achieve this using for-loops:
An example:
Before running script:
Script:
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var keys = sheet.getRange('A1:A5').getValues();
var values = sheet.getRange('B1:B5');
for (var i = 0; i < keys.length; i++){
isMatch(keys[i], values);
}
}
function isMatch(key, values) {
for(var i=0; i< values.getNumRows(); i++){
var sample = values.getValues()[i];
if (key[0] == sample[0]) {
values.getCell(i+1, 1).offset(0,1).setValue(values.getCell(i+1, 1).offset(0,1).getValue()+key[0]);
}
}
}
After running script:

Related

Google Apps Script: Loop through a list

I have a deleteEachRow function that loops through a sheet and delete Rows that have a particular Column Value.
This works fine and was hoping to modify it in such a way that it loops through a multile sheets in the work-book and also delete rows based on multiple Column Values.
The deleteRow() script
//GLOBALS
var SS = SpreadsheetApp.openById("sheetID");
var SHEET = SS.getSheetByName("Sheet1");
var RANGE = SHEET.getDataRange();
var DELETE_VAL = "abc";
var COL_TO_SEARCH = 4; // The column to search for the DELETE_VAL (Zero is first)
function deleteEachRow(){
var rangeVals = RANGE.getValues();
//Reverse the 'for' loop.
for(var i = rangeVals.length-1; i >= 0; i--){
if(rangeVals[i][COL_TO_SEARCH] === DELETE_VAL){
SHEET.deleteRow(i+1);
};
};
};
What I have tried..
var SHEET = SS.getSheetByName(["Sheet1", "Sheet2"]);
var DELETE_VAL = ["abc","DEF"];
function deleteEachRow(){
var rangeVals = RANGE.getValues();
//Reverse the 'for' loop.
for(var i = rangeVals.length-1; i >= 0; i--){
for(var i=0; size = DELETE_VAL.length; i < size; i++){
if(rangeVals[i][COL_TO_SEARCH] === DELETE_VAL[i]){
for(var i=0; size = SHEET.length; i < size; i++){
SHEET[i].deleteRow(i+1);
};
};
};
};
};
Which completes executing from my logs, but does not actually work. I may have murdered some logic here, please pardon me, I am new to .gs/.js.
Thanks for your anticipated response.
Issue : You're passing array to getSheetByName, whereas as per documentation it accepts String only. i.e. Name of the single sheet you want to fetch.
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#getsheetbynamename
So you can modify your function to take sheet name as input and then delete rows in that sheet. Then call your function with desired sheet names. Something like this:
var spreadSheet = SpreadsheetApp.openById("sheetID");
var DELETE_VAL = "abc";
var COL_TO_SEARCH = 4; // The column to search for the DELETE_VAL (Zero is first)
function deleteEachRow(sheetName){
var SHEET = spreadSheet.getSheetByName(sheetName);
var RANGE = SHEET.getDataRange();
var rangeVals = RANGE.getValues();
// existing logic
};
// Invoke deleteEachRow() for each sheet you want to delete the rows
["Sheet1", "Sheet2"].forEach((sheetName) => deleteEachRow(sheetName));
Umair is right, there was a simply error in the first line. But I'd want to add that the sheet.deleteRow(row) is not the best practice in case if there are many rows to delete. This command is quite time consuming.
If you have more than dozen rows to delete it's better to grab all data from a sheet (or range) var data = range.getValues(), clear the sheet (or the range), to process the array inside the script and refill the sheet back with new data new_range.setValues(array). It will work much faster.

How to reference a specific list of cells that contain spreadsheet ids, to use in a loop?

I have one master sheet that handles a bunch of other spreadsheets, in the sense that the master has a whole bunch of importranges that pull specific info from the child ss's, the child ss's are identical in function, but not in data. Each of the child spreadsheets has their own automated scripts that pertain to each individual ss, but I want any script that affects every ss in an equivalent way to be run from one master sheet. All Child ss's have an identical structure, so the first sheet is named main, which pulls in a bunch of data from the other sheets on that same ss.
Basically, I need to run the exact same function on about 30 spreadsheets, and figured I could make 1 spreadsheet that had one script that would loop through the list of spreadsheets. Preferably, the list of spreadsheet ids is in plain text in a set of cells on the main spreadsheet (Lets say Main!B5:B), so that I could add a new spreadsheet id to the list, and any new spreadsheets that I add would also run the script when I run it.
function myFunction() {
// This next line is what I'm not sure how to do
// var ssList = [ Cell B5, Cell B6 ... ];
var len = ssList.length
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
// Spreadsheet loop
for (var i = 0; i < len; i++) {
var TargetSheet = SpreadsheetApp.openById(ssList[i]);
}
}
This should work and you look to be on the right track, but you need to reference the specific column in each row which contains the ID.
getValues() returns a two dimensional array ("array of arrays"), each row is an array of cells. Right now you are passing the entire row to openById, instead of a specific cell.
You don't need to hardcode the list of cells containing IDs into your script, instead just rely on the data that is in your spreadsheet.
For example, if the spreadsheet IDs are in Column A, you need to reference the value at index 0 of the row:
var TargetSheet = SpreadsheetApp.openById(values[i][0]);
Or if the spreadsheet ID's are in Column B, that would be index 1 of the row:
var TargetSheet = SpreadsheetApp.openById(values[i][1]);
To get the value of "len", you can refer to the length of values, the total number of rows in the data range.
var len = values.length;
Fully modified code would look like this:
function myFunction() {
var rows = sheet.getDataRange();
var values = rows.getValues();
var rowsDeleted = 0;
// Spreadsheet loop
for (var i = 0; i < values.length; i++) {
var TargetSheet = SpreadsheetApp.openById(values[i][1]); //get all values from column "B" (index 1)
}
}
function myFunctionxx() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Main');
const rg=sh.getRange(5,2,sh.getLastRow()-4,1);
var list=rg.getValues().map(function(r){return r[0];});//the map flatten a column into 1 dimensional array
list.forEach(function(ssid){ //the forEach iterates through the list the first parameter is the value of the array, the second parameter which is not used in this case is the index
myOtherfunction(ssid);//This is the function that you want to perform on each of the spreadsheets and I'm passing the the spreadsheet id to it.
});
}
You can read more about the Array map and forEach method here

How to copy values from one sheet and paste them into another using Google Sheets Macros?

I'm writing a Google Sheets Macros without having a lot of knowledge about syntax.
What I want to do is the following:
I want to copy the values which are matching in a source matrix into another table. However, I don't know how to write that as a Macros.
I've written the following code:
function CalcularCruces() {
var spreadsheet = SpreadsheetApp.getActive();
var sourceSheet = spreadsheet.getSheetByName("Cruces Activo-Amenazas");
var destinationSheet = spreadsheet.getSheetByName("AnĂ¡lisis de Riesgos");
/** Total number of left column values from source table **/
const maxAmenazas = 29;
for(var i = 0; i < maxAmenazas; i++) {
/** Now I need to get the column and row values which are matching with the checkbox
and paste them into another table **/
}
};
Here is an example of the input table and how the output table should look like after executing the macros.
Input Table Sheet
Output Table Sheet
Edit:
I need the data to be written next to this static columns:
Actual Output
Desired Output
You can do the following:
Retrieve the data from the source sheet via getDataRange and getValues.
For each row in this data (excluding the headers row, that has been retrieved and removed from the array with shift), check which columns have the checkbox marked.
If the corresponding checkbox is marked, write the corresponding values to the destination sheet with setValues.
It could be something like this:
function CalcularCruces() {
var spreadsheet = SpreadsheetApp.getActive();
var sourceSheet = spreadsheet.getSheetByName("Cruces Activo-Amenazas");
var destinationSheet = spreadsheet.getSheetByName("AnĂ¡lisis de Riesgos");
destinationSheet.getRange("A2:B").clearContent();
var values = sourceSheet.getDataRange().getValues(); // 2D array with all data from source sheet
var headers = values.shift(); // Remove and retrieve the headers row
for (var i = 1; i < values[0].length; i++) { // Iterate through each column
for (var j = 0; j < values.length; j++) { // Iterate through each row
var activo = values[j][0]; // Activo corresponding to this row
if (values[j][i]) { // Check that checkbox is marked
// Get the row index to write to (first row in which column A and B are empty):
var firstRow = 2;
var firstCol = 1;
var numRows = destinationSheet.getLastRow() - firstRow + 1;
var numCols = 2;
var firstEmptyRow = destinationSheet.getRange(firstRow, firstCol, numRows, numCols).getValues().filter(function(row) {
return row[0] !== "" && row[1] !== "";
}).length + firstRow;
// Write data to first row with empty columns A/B:
destinationSheet.getRange(firstEmptyRow, firstCol, 1, numCols).setValues([[headers[i], activo]]);
}
}
}
};
Notes:
All data is added to the target sheet every time the script is run, and this can lead to duplicate rows. If you want to avoid that, you can use clearContent at the beginning of your script, after declaring destinationSheet, to remove all previous content (headers excluded):
destinationSheet.getRange("A2:B").clearContent();
In this sample, the number of amenazas is not hard-coded, but it dynamically gets the number of rows in the source sheet with getValues().length. I'm assuming that's a good outcome for you.
UPDATE: Since you have other columns in your target sheet, you cannot use appendRow but setValues. First, you have to find the index of the first row in which columns A and B are empty. This is achieved with filtering the array of values in columns A-B and filtering out the elements in which the two values are empty (with filter).
Reference:
Sheet.getDataRange
Range.getValues
Array.prototype.shift()
Sheet.appendRow(rowContents)
Array.prototype.filter()
Range.clearContent()

Use Google Apps Script to loop through the whole column

I am trying to loop through the whole row in my google sheet and copy some of the data from one sheet to another. The list will get longer over time.
More specifically: If input in column B equals "blue", than copy the values from column A and C into another sheet.
Do this for all columns till the end of the column.
Link to my spreadsheet: https://docs.google.com/spreadsheets/d/1xnLygpuJnpDfnF6LdR41gN74gWy8mxhVnQJ7i3hv1NA/edit?usp=sharing
The loop stops when the colour does not equal blue. Why?
As you can see I used a for loop. Is that even the way to go?
Can I do anything about the speed of the code execution?
Any comments, hints or help are highly appreciated.
Regards!
You had the input sheet named "List" and I named the output sheet "Output". And here's the code.
function condCopy()
{
var s = SpreadsheetApp.getActiveSpreadsheet();
var sht = s.getSheetByName('List')
var drng = sht.getDataRange();
var rng = sht.getRange(2,1, drng.getLastRow()-1,drng.getLastColumn());
var rngA = rng.getValues();//Array of input values
var rngB = [];//Array where values that past the condition will go
var b = 0;//Output iterator
for(var i = 0; i < rngA.length; i++)
{
if(rngA[i][1] == 'blue')
{
rngB[b]=[];//Initial new array
rngB[b].push(rngA[i][0],rngA[i][2]);
b++;
}
}
var shtout = s.getSheetByName('Output');
var outrng = shtout.getRange(2,1,rngB.length,2);//Make the output range the same size as the output array
outrng.setValues(rngB);
}
You have 2 options. The first is to use the standard query() function from Google Sheets to get the values. The downside here is that it is only a reference of the values. So you cannot reorder them, etc. To use this, place this in cell A1 and it will pull the Headers and retrieve the values from column A and C:
=QUERY(A:C, "select A, C where B = 'blue'", 1)
For a Google Apps Script answer:
This will loop through your List sheet and for every row where column B is blue it will save the values in column A and C to column A and B of the new sheet:
function doIt(){
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet4");
var lastRow = activeSheet.getLastRow();
var lastCol = activeSheet.getLastColumn();
var targetValues = [];
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("List");
var lastSourceRow = sourceSheet.getLastRow();
var lastSourceCol = sourceSheet.getLastColumn();
var sourceRange = sourceSheet.getRange(1, 1, lastSourceRow, lastSourceCol);
var sourceData = sourceRange.getValues();
var activeRow = 0;
//Loop through every retrieved row from the Source
for (row in sourceData) {
//IF Column B in this row has 'blue', then work on it.
if (sourceData[row][1] === 'blue') {
//Save it ta a temporary variable
var tempvalue = [sourceData[row][0], sourceData[row][2]];
//then push that into the variables which holds all the new values to be returned
targetValues.push(tempvalue);
}
}
//Save the new range to the appropriate sheet starting at the last empty row
activeSheet.getRange(lastRow + 1, 1 , targetValues.length, 2).setValues(targetValues);
}
Of course, you could pass the value to test to the function by replacing 2 lines. The first, defining the function:
function doIt(testingvar){
to pass a variable called testingvar, and the test line to replace the hard coded test with the passed variable:
if (sourceData[row][1] === testingvar) {

Data copying with Google Apps Script

I am trying to write a script in Google Apps Script that takes cell information from one sheet and copies it to another sheet, both for just grabbing certain columns to display on the second sheet and also a condition based on the values inside cells in a certain column. Here is what I have so far:
function onMyEdit() {
var myMaster = SpreadsheetApp.openById("xxxxx");
var masterSheet = myMaster.setActiveSheet(myMaster.getSheets()[0]);
var myNames = SpreadsheetApp.openById("xxxxx");
var namesSheet = myNames.setActiveSheet(myNames.getSheets()[0]);
var row1 = masterSheet.getRange(1, 1, masterSheet.getLastRow(), 1);
var rowV = row1.getValues();
var firstArray = masterSheet.getDataRange().getValues();
var dataList = [];
for (var i = 1; i < rowV.length; i++) {
dataList.push(firstArray[i][0]);
dataList.push(firstArray[i][1]);
dataList.push(firstArray[i][2]);
dataList.push(firstArray[i][3]);
}
for (var j = 0; j < rowV.length - 1; j++) {
namesSheet.getRange(2, j + 1, 1, 1).setValue(dataList[j]);
}
}
So as of now it only works on one row, starting from the second row (to allow for column headers). And I suppose when I want to grab rows conditionally based on cell data, I will use an 'if' statement for the condition inside the 'for' loop, but I want the data to copy to the next available row in both sheets. I suppose I'd use something like:
' getLastRow + 1 '
or something like that. I need this code to be as efficient as possible because of the amount of data and its purpose. I am pretty new to programming so please explain in detail, and thanks again.
I'm not sure I understood exactly what you wanted to do but -from what I understood- this code snippet should give you a better way to start with...
(I added a few comments to explain in the code itself)
function onMyEdit() {
var myMaster = SpreadsheetApp.openById("MasterSheet ID");
var masterSheet = myMaster.getSheets()[0]; // get 1rst sheet
var myNames = SpreadsheetApp.openById("NamesSheet ID");
var namesSheet = myNames.getSheets()[0]; // get 1rst sheet
var firstArray = masterSheet.getDataRange().getValues();
var dataList = [];
for ( r = 1; r < firstArray.length; r++) { // iterate the first col of masterSheet
if(firstArray[r][0]=='some condition'){ // if value in the first column == 'some condition get the second column cell in the new array (here you could change what you want to get)
dataList.push([firstArray[r][1]])
}
}
Logger.log(dataList)
if(dataList.length>0){
namesSheet.getRange(1,namesSheet.getLastColumn()+1,dataList.length,1).setValues(dataList);//copy data in a column after last col
}
}

Categories

Resources