Setting array values across row in Google Sheets - javascript

I have an array pulled from a Google Sheet column using the following code. How can I distribute these values across a row inside of a different sheet? Essentially, I would like the value at decisionPoint[1] to populate cell 'B2', decisionPoint[2] to populate cell 'C2', decisionPoint[3] to populate cell 'D2', and so on. Thanks in advance for any help!
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); // get the spreadsheet object
var decisionPointSheet = spreadsheet.getSheets()[2]; // set decision point sheet
var lastDecisionPoint = decisionPointSheet.getDataRange().getLastRow();
var decisionPoints = decisionPointSheet.getDataRange().getValues();
for ( var i = 1; i < lastDecisionPoint; i++){
Logger.log(decisionPoints[i][0]);
}

You may try that:
function transpose(){
var input = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Requests"); // origin sheet
var out = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("output"); // destination sheet
var data = input.getDataRange().getValues();
data.shift(); // remove first row (apparently you are not taking the title)
var output = []; // better to create your object and then push it at once - it run faster
for(var i in data){ // I prefer that than the classical var i =1;i<numCol ....
if(i<10) output.push(data[i][0]);
}
out.getRange(4, 1,1,output.length).setValues([output]); // i you want to specify the row where it need to end
// out.appendRow(output); // or you can change for that just to appen a new row
}

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 Dynamic Paste values after Last Row [Google Script]

I am building a script to copy a row in another spreadsheet. The idea is to have one sheet with the inputs that are going to be stored in a second spreadsheet. However, I am facing some real struggle in building the dynamic paste range. This is the point I was able to reach with my present knowledge:
function Export() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var database = SpreadsheetApp.openById("xxx");
var source = ss.getSheetByName('yyy');
var dataToCopy = source.getRange('bb').getValues();
var copyToSheet = database.getSheetByName("zzz");
var copyData = copyToSheet.getRange('bb').setValues(dataToCopy)
var Clean = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('yyy').getRange('bb');
Clean.clear({contentsOnly:true});
}
This script copy a range into a fixed range in a second spreadsheet, and it clears the values present in the source. My question is: How can I create a range that makes the script paste the data in the first blank row in the second spreadsheet?
I tried some combination of appendRow, getLastRow, insertRowAfter, but I was not able to get it done.
Thank you for your time!
This is what I was able to achieve with the help of a friend:
function Export2() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var database = SpreadsheetApp.openById("1UfKqXCMNIbjh3ge7s26SNkXyGez-bY3fvl6_3-RQKos");
var source = ss.getSheetByName('Sheet26');
var dataToCopy = source.getRange('A1:E1');
var copyToSheet = database.getSheetByName("TOT");
var lastRow = copyToSheet.getLastRow();
for (var i = 1; i<6 ;i++){
var Paste = copyToSheet.getRange(lastRow + 1,i).setValue(dataToCopy.getCell(1, i).getValue());
}
var Clean = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet26').getRange('A1:E1');
Clean.clear({contentsOnly:true});
}
Below is a script that will do the thing you want to do dynamically without the use of named ranges. It assumes that all the data on the source sheet should be copied over to the destination sheet. Let me know if you need any additional explanation beyond what is provided in the comments.
function Export() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var database = SpreadsheetApp.openById("xxx");
var source = ss.getSheetByName('yyy');
var dataToCopyRng = source.getDataRange(); //Gets range object of all data on source sheet
var dataToCopy = dataToCopyRng.getValues(); //Gets the values of the source range in a 2 dimensional array
var copyToSheet = database.getSheetByName("zzz");
var copyData = copyToSheet.getRange(copyToSheet.getLastRow()+1,1,dataToCopy.length,dataToCopy[0].length).setValues(dataToCopy)
//Explination of the above command is as follows getRange(row, column, numRows, numColumns)
//--row is copyToSheet.getLastRow()+1 -- finds last row with content and adds one
//--Column is 1 for Column A
//--numRows is the length of the array (how many rows are in the array of values)
//--numcolumns is the length of the first element of the 2 dimensional array (arrays start at zero). The length of the first element is how many columns are in the array
//--combine the above with .getRange and you get the range object that is an exact match to the array of source data rows and columns
//--then you simply set the values of this range with the source data
dataToCopyRng.clear({contentsOnly:true});
}
You can learn more about 2 dimensional arrays here.
Cheers!

Paste values from one Google Sheet to another and remove duplicates based on ID column

I have a similar situation to the one described on this question: two worksheets, with input data coming into the Feed sheet using the importxml function and a Data sheet where new rows get copied thanks to a script set to run daily.
However, the current script is creating daily duplicates. As such, I would like to adapt the answer provided on the question above so that the script checks the IDs on column F and only copies the rows with new IDs.
How should I update the section below that creates a hash to one that looks for the IDs on column F instead? Also my rows are consistent, so is it correct to assume I can just remove the relevant code lines towards the end?
The sample Google Sheet is available here.
function appendUniqueRows() {
var ss = SpreadsheetApp.getActive();
var sourceSheet = ss.getSheetByName('Get Data');
var destSheet = ss.getSheetByName('Final Data');
var sourceData = sourceSheet.getDataRange().getValues();
var destData = destSheet.getDataRange().getValues();
// Check whether destination sheet is empty
if (destData.length === 1 && "" === destData[0].join('')) {
// Empty, so ignore the phantom row
destData = [];
}
// Generate hash for comparisons
var destHash = {};
destData.forEach(function(row) {
destHash[row.join('')] = true; // could be anything
});
// Concatentate source rows to dest rows if they satisfy a uniqueness filter
var mergedData = destData.concat(sourceData.filter(function (row) {
var hashedRow = row.join('');
if (!destHash.hasOwnProperty(hashedRow)) {
// This row is unique
destHash[hashedRow] = true; // Add to hash for future comparisons
return true; // filter -> true
}
return false; // not unique, filter -> false
}));
// Check whether two data sets were the same width
var sourceWidth = (sourceData.length > 0) ? sourceData[0].length : 0;
var destWidth = (destData.length > 0) ? destData[0].length : 0;
if (sourceWidth !== destWidth) {
// Pad out all columns for the new row
var mergedWidth = Math.max(sourceWidth,destWidth);
for (var row=0; row<mergedData.length; row++) {
for (var col=mergedData[row].length; col<mergedWidth; col++)
mergedData[row].push('');
}
}
// Write merged data to destination sheet
destSheet.getRange(1, 1, mergedData.length, mergedData[0].length)
.setValues(mergedData);
}
I'm a novice in this world of Google Apps scripts, so do please let me know if I'm missing any crucial information. Thanks in advance for the help.
You want to copy the values from "Feed" sheet to "Data" sheet.
When the values are copied, you want to copy only new values which are not included in "Data" sheet.
You want to choose the new values using the values of column "F".
If my understanding for your question is correct, how about this modification? In this modification, I modified the script in your shared spreadsheet.
Modification points:
In your script, all values of "Feed" sheet are copied to "Data" sheet. So in order to choose only new values, I used the following flow.
Retrieve the values from column "F". This is used for choosing the new values.
Retrieve the new values using the values from column "F".
Put the new values to "Data" sheet.
The script which reflected above flow is as follows.
Modified script:
From:
This is your script in the shared spreadsheet. Please modify this script to below one.
function Copy() {
var sss = SpreadsheetApp.openById('#####'); // this is your Spreadsheet key
var ss = sss.getSheetByName('Feed'); // this is the name of your source Sheet tab
var range = ss.getRange('A3:H52'); //assign the range you want to copy
var data = range.getValues();
var tss = SpreadsheetApp.openById('#####'); //replace with destination ID
var ts = tss.getSheetByName('Data'); //replace with destination Sheet tab name
ts.getRange(ts.getLastRow()+1, 1,50,8).setValues(data);// 49 value refers to number of rows, 8 to columns
}
To:
function Copy() {
var sss = SpreadsheetApp.openById('#####'); // this is your Spreadsheet key
var ss = sss.getSheetByName('Feed'); // this is the name of your source Sheet tab
var range = ss.getRange('A3:H52'); //assign the range you want to copy
var data = range.getValues();
var tss = SpreadsheetApp.openById('#####'); //replace with destination ID
var ts = tss.getSheetByName('Data'); //replace with destination Sheet tab name
// Below script was added.
var values = ts.getRange("F3:F").getValues().filter(String);
var copiedValues = data.filter(function(e) {return !values.some(function(f){return f[0] == e[5]}) && e.filter(String).length > 0});
ts.getRange(ts.getLastRow() + 1, 1, copiedValues.length, copiedValues[0].length).setValues(copiedValues);
}

Update data from a Spreadsheet - Apps Script

I'm doing a data transfer of several spreadsheets to a single one, what I do is transfer the last data of certain columns to the master spreadsheet and also insert them in the last available row of certain columns, for now, I insert all the data but I would like to to know how I can have it examine the master spreadsheet so that if those data already exist, it does not delete them but update them. The script that I have is the following ...
function Gas10(){
var ss1 = SpreadsheetApp.openById("ID");
var ssh1 = ss1.getSheetByName("Sheet 1");
var lastRow1 = ssh1.getLastRow();
var gtRange1 = ssh1.getRange("C"+(lastRow1)+":K"+(lastRow1)).getValues();
var gtRange2= ssh1.getRange("A" + (lastRow1)).getValue();
var ss2 = SpreadsheetApp.getActiveSpreadsheet();
var ssh2 = ss.getSheetByName("Sheet 2");
var lastRow2 = ssh2.getLastRow() + 1;
var setRange1 = ssh2.getRange(lastRow2, 4, gtRange1.length, gtRange1[0].length).setValues(gtRange1);
var setRange2 = ssh2.getRange(lastRow2, 3).setValue(gtRange2);
}
I need to know how I can do it when I insert a piece of information (I already do that), but update it if it already exists. This is the example that I created so that it can be better understood, in this example I have two sheets of which from sheet 1 I pass data to sheet 2 and what I'm looking for is that sheet 2 updates all the data that are equal to (Name, Num, Proyect). I hope that now I understand better what I'm looking for.
Basically what you have to do is
get the new Line you want to add to the destination spreadsheet
get all the required datas of the destination spreadsheet
Check if the new Line datas have the same datas than in the destination data array
If so change ID value
paste changed datas in the destination spreadsheet
based on this spreadsheet The code should look something like this
function Gas10(){
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var ssh1 = ss1.getSheetByName("Sheet 1");
var ssh2 = ss1.getSheetByName("Sheet 2");
var lastRow1 = ssh1.getLastRow();
var lastCol1 = ssh1.getLastColumn();
var newLine = ssh1.getRange(lastRow1, 2, 1, lastCol1 - 1 ).getValues();
var destDatas = ssh2.getDataRange().getValues();
for (var i = 1; i < destDatas.length; i++)
{
if (newLine[0][0] == destDatas[i][0]
&& newLine[0][1] == destDatas[i][1]
&& newLine[0][2] == destDatas[i][2])
{
destDatas[i][3] = newLine[0][3];
}
}
// add newLine to destDatas
destDatas.splice(destDatas.length, 0, newLine[0]);
var lastColumn = ssh2.getLastColumn();
var lastRow2 = ssh2.getLastRow() + 1;
ssh2.getRange(1, 1, destDatas.length, lastColumn).setValues(destDatas);
ssh1.deleteRow(lastRow1);
}
Here's an example I played around with:
It looks at the slave sheet for any data. When it finds data it puts the row and col and value into an obj which is then added to an array. When it finishes it calls the updMaster which then looks for data in those same cells (assuming that the cells are in the same place if those cells are blank then it adds data and I also changed the background to lightblue to show me where it updated the cells.
You could run the getSlaveData() for different sheets if you wish.
function getSlaveData(){
var ss=SpreadsheetApp.getActive();
var ssh=ss.getSheetByName('Sheet2');
var sA=[];
var srg=ssh.getDataRange();
var svA=srg.getValues();
for(var i=0;i<svA.length;i++){
for(var j=0;j<svA[i].length;j++){
//if(svA[i][j]){
if(!ssh.getRange(i+1,j+1).isBlank()){//optional way to look for values
var sObj={};
sObj['row']=i + 1;
sObj['col']=j + 1;
sObj['value']=svA[i][j];
sA.push(sObj);
}
}
}
updMaster(sA);
}
function updMaster(sA){
var ss=SpreadsheetApp.getActive();
var msh=ss.getSheetByName('Sheet1');
for(var i=0;i<sA.length;i++){
if(msh.getRange(sA[i].row,sA[i].col).isBlank()){
msh.getRange(sA[i].row,sA[i].col).setValue(sA[i].value);
msh.getRange(sA[i].row,sA[i].col).setBackground('lightblue');
}
}
}

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) {

Categories

Resources