I'm using app script to get an HTML page
everything works fine
except that I need to exclude column B+C from the range
function doGet() {
return HtmlService.createTemplateFromFile('Index').evaluate()
.setTitle("Performance Efficiency");//We can set title from here
}
//GET DATA FROM GOOGLE SHEET AND RETURN AS AN ARRAY
function getData() {
var spreadSheetId = "Sheet ID"; //CHANGE
var dataRange = "Data!A3:P"; //CHANGE
var range = Sheets.Spreadsheets.Values.get(spreadSheetId, dataRange);
var values = range.values;
return values;
}
In your situation, how about the following modification?
From:
var values = range.values;
To:
var srcValues = range.values;
var temp = srcValues[0].map((_, c) => srcValues.map(r => r[c])).filter((_, c) => ![2, 3].includes(c + 1));
var values = temp[0].map((_, c) => temp.map(r => r[c]));
In this modification, at first, the value of range.values is transposed and remove the columns "B" and "C", and then, the values are transposed. By this, the values except for the columns "B" and "C" can be retrieved.
References:
map()
filter()
Related
I have this code snippet:
function getTimeFrames(){
var ss = SpreadsheetApp.getActive();
var cell = ss.getRange("C1").getValue();
Logger.log(cell);
var s = ss.getSheetByName(cell).getRange("M2:M");
var unique = new Set(s.getValues());
unique.forEach(x => Logger.log(x))
}
This code would be called from a Google Sheets spreadsheet which serves as an UI, where the C1 cell would be a name of a sheet used for storing data. In that sheet I have a column (M) that I need to get the unique values out of in order to store in a drop-down in the UI sheet.
The problem I have is that I can't get the unique values part working at all. Throughout my experimentation, I would either get a list of all the values of column M or no Logging output at all.
Any help is greatly appreciated!
Try
function getTimeFrames(){
var ss = SpreadsheetApp.getActive();
var cell = ss.getRange("C1").getValue();
Logger.log(cell);
var unique = ss.getSheetByName(cell).getRange("M2:M").getValues().flat().filter(onlyUnique)
console.log(unique)
}
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
This was really a tough job before ES6. But now, with a combination of filter() and indexOf() you can easily pull it off.
For Example:
var List = ['One','Two','Two','One','One','Two','One','Three']
const uniqueList = (value,index,self) =>
{return self.indexOf(value) ===index;}
var finalUniqueList =List.filter(unique);
Try spreading the unique values into an array:
function getTimeFrames() {
const sheet = SpreadsheetApp.getActive()
const cell = sheet.getRange(`C1`).getValue()
const values = sheet.getSheetByName(cell)
.getRange(`M2:M`)
.getValues()
.filter(String)
.flat()
const unique = [...new Set(values)]
Logger.log(unique)
}
The goal is to delete empty cells in Column N alone, without disturbing the other columns and shift the rest of the cells upwards to obtain a compact column with just non empty cells. There can and will be empty cells after the result of course.
Please suggest a method
function Defaulters() {
var spreadsheet = SpreadsheetApp.getActive();
var as = spreadsheet.getActiveSheet();
//to get the last row of the Column
var lastRow = 100;
var range = as.getRange("N" + lastRow);
if (range.getValue() !== "")
{Logger.log(lastRow);}
{lastRow = range.getNextDataCell(SpreadsheetApp.Direction.UP).getRow();}
Logger.log(lastRow);
//to delete the empty cells and give a compact output of just names and emails in the Column
for (var l=lastRow; l>=3; l--)
{if(as.getRange(l,14).getValue() == "")
Logger.log(true); **//what to put here to delete this cell?**
else
Logger.log(false);**// what to put here to retain this cell?**
}
}
I'd try something like this:
function myFunction() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues(); // get all data
const data_new = data.filter(row => row[13] != ''); // filter the data by column 'N'
sheet.clearContents(); // clean the sheet
sheet.getRange(1,1,data_new.length,data_new[0].length)
.setValues(data_new); // put the new data back on the sheet
}
Or even like this:
function myFunction() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues().filter(row => row[13] != '');
sheet.clearContents().getRange(1,1,data.length,data[0].length).setValues(data);
}
If you need to keep all the table intact and remove empty cells only from column 'N' it can be done this way:
function clean_column_N() {
const sheet = SpreadsheetApp.getActiveSheet();
const range = sheet.getRange('N3:N'+sheet.getLastRow()) // get a range start from row 3
const data = range.getValues().filter(String); // get a data and remove empty elements
range.clearContent().offset(0,0,data.length).setValues(data); // put the data back on the sheeet
}
All data in column 'N' will be moved upward.
Update
Modified last variant to clean any column:
function main() {
clean_column('N');
clean_column('O');
}
function clean_column(col) {
const sheet = SpreadsheetApp.getActiveSheet();
const range = sheet.getRange(col + '3:' + col + sheet.getLastRow());
const data = range.getValues().filter(String);
range.clearContent().offset(0,0,data.length).setValues(data);
}
I have a google spreadsheet data in form of array. Now I want to push the array position I used for loop which is working fine on small data but when the data length is increased it result in delay.
Is there a faster way to push the array position in the array.
Here is the code which I am currently using:-
var ss = SpreadsheetApp.openById('19zxxxxxxxxxxxxxxxxxxxxxxxxOI');
var sheet1 = ss.getSheetByName('Sheet2');
var data = sheet1.getRange("A:H").getValues();
var email = Session.getActiveUser().getEmail();
for(var i = 0; i < data.length; i++)
{
data.unshift(i+1);
} // this for loop takes too much time.
data = data.filter(function(item){return item[7] == email});
var x = data.map(function(val){
return val.slice(0, -7);
})
Logger.log(x)
return x;
}
I believe your goal as follows.
If data.unshift(i+1) is data[i].unshift(i+1) as TheMaster's comment, you want to retrieve the values of the column "A" when the value of column "G" is the same with email. At that time, you want to add the row number to the 1st index of the row value.
From your script, I understood like this.
You want to reduce the process cost of this situation.
For this problem, how about this solution?
Pattern 1:
In this pattern, your script is modified. In this case, the result values are retrieve by one loop.
Sample script:
function myFunction() {
var ss = SpreadsheetApp.openById('19zxxxxxxxxxxxxxxxxxxxxxxxxOI');
var sheet1 = ss.getSheetByName('Sheet2');
var data = sheet1.getRange("A1:H" + sheet1.getLastRow()).getValues(); // Modified
var email = Session.getActiveUser().getEmail();
const res = data.reduce((ar, [a,,,,,,g], i) => { // Modified
if (g == email) ar.push([i + 1, a]);
return ar;
}, []);
Logger.log(res)
return res;
}
Pattern 2:
In this pattern, as other method, TextFinder and Sheets API are used. In this case, the size of base data by searching email with TextFinder can be reduced. And each values are retrieved by one API call using Sheets API.
Sample script:
Before you use this script, please enable Sheets API at Advanced Google services.
function myFunction() {
const spreadsheetId = '19zxxxxxxxxxxxxxxxxxxxxxxxxOI';
const ss = SpreadsheetApp.openById(spreadsheetId);
const sheet = ss.getSheetByName('Sheet2');
const email = Session.getActiveUser().getEmail();
// 1. Retrieve the ranges of rows by searching "email" at the column "G".
const ranges = sheet.getRange("G1:G" + sheet.getLastRow()).createTextFinder(email).findAll();
// 2. Create an object for using with Sheets API.
const reqs = ranges.reduce((o, e) => {
const row = e.getRow();
o.rows.push(row);
o.ranges.push("A" + row);
return o;
}, {rows: [], ranges: []});
// 3. Retrieve values and add the row number.
const res = Sheets.Spreadsheets.Values.batchGet(spreadsheetId, {ranges: reqs.ranges})
.valueRanges
.map((e, i) => ([reqs.rows[i], e.values[0][0]]));
Logger.log(res)
return res;
}
If email is included other string, please use matchEntireCell(true) to TextFinder.
References:
reduce()
Advanced Google services
Method: spreadsheets.values.batchGet
The following code works successfully to compare column A of sheet 2 with Column B of sheet 1, any matches will copy the entire row to sheet 3. However im needing a very slight change of this code that compares column A of sheet 2 to column N of sheet 1 instead of column B. Could someone help me with this code change?
Here is the link to the previous post Java script optimization for a google apps script
function copyRowtoSheet3() {
var spreadsheetId = "1Aw11LiKzyezfrTQIuTsJPhUFtz8RPqLCc8FlIiy0ZlE";
var ss = SpreadsheetApp.openById(spreadsheetId);
var s1 = ss.getSheetByName('Sheet1');
var s2 = ss.getSheetByName('Sheet2');
// 1. Retrieve values from "Sheet1" and "Sheet2",
var values1 = s1.getDataRange().getValues();
var values2 = s2.getRange(1, 1, s2.getLastRow(), 1).getValues();
// 2. Create an object using values2.
var obj = values2.reduce((o, [e]) => {
o[e] = null;
return o;
}, {});
// 3. Create resultArray using values1 and obj.
var resultArray = values1.filter(([,b]) => b in obj);
// 4. Put resultArray to Sheet3.
Sheets.Spreadsheets.Values.update({values: resultArray}, spreadsheetId, "Sheet3", {valueInputOption: "USER_ENTERED"});
}
What I have attempted is:
var resultArray = values1.filter(([,n]) => n in obj);
However that did not work. Any ideas?
You want to retrieve the values of "Sheet1" and "Sheet2".
You want to compare the column "N" of "Sheet1" and the column "A" of "Sheet2". When the values of the column "N" of "Sheet1" and the column "A" of "Sheet2" are the same, you want to retrieve the row of "Sheet1" and put to "Sheet3".
You want to achieve this by modifying your script.
Modification point:
var resultArray = values1.filter(([,b]) => b in obj); is modified. In your current script, the column "B" from [,b] is compared.
Modified script:
When your script is modified, please modify as follows.
From:
var resultArray = values1.filter(([,b]) => b in obj);
To:
var resultArray = values1.filter(b => b[13] in obj);
Using Google Sheet, data were entered into cells before the data gets transferred into a 'database' page.
Problem:
1) After the transfer completed, previous entries were replaced by the new entries.
2) Database would start at a different row (i.e. row 35) instead of row 1.
Question: What caused the two problems, and how to solve the problems?
Below is my script. Thanks in advance!
function setValue(cellName, value) {
SpreadsheetApp.getActiveSpreadsheet().getRange(cellName).setValue(value);
}
function getValue(cellName) {
return SpreadsheetApp.getActiveSpreadsheet().getRange(cellName).getValue();
}
function getNextRow() {
return SpreadsheetApp.getActiveSpreadsheet().getLastRow() + 1;
}
function addTrade(a,b,c,d,e,f,g) {
var row = getNextRow();
setValue('Meta4!B' + row, a);
setValue('Meta4!C' + row, b);
setValue('Meta4!D' + row, c);
setValue('Meta4!E' + row, d);
setValue('Meta4!F' + row, e);
setValue('Meta4!G' + row, f);
setValue('Meta4!H' + row, g);
}
function submitTrade() {
addTrade(new Date(), getValue('Dashboard!N3'), getValue('Dashboard!N4'), getValue('Dashboard!N5'), getValue('Dashboard!N6'), getValue ('Dashboard!N7'), getValue('Dashboard!N8'));
var app = SpreadsheetApp;
var activeSheet = app.getActiveSpreadsheet().getActiveSheet();
activeSheet.getRange('Dashboard!N3:O8').clearContent();
}
Possible Issues:
getLastRow executed on a incorrect sheet
Possible datavalidation dropdowns/unrecognised values up to row 35
Code repeats
Solutions
Get sheet first and then execute getLastRow
Remove Data validations from sheet
Use DRY principle
Flow:
Get source sheet values as a array, add current date to it and transpose the array.
Get lastRow from target sheet and setValues the modified array.
Sample Script:
function transposeWithDate() {
var cfg = {
ssh: 'Dashboard',//sourceSheet
sRng: 'N3:N8',//sourceRange
tsh: 'Meta4',//targetSheet
dt: new Date(),
};
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getSheetByName(cfg.ssh);
var values = source.getRange(cfg.sRng).getValues(); //[[1],[2],[3]]
var target = ss.getSheetByName(cfg.tsh);
var lastRow = target.getLastRow();
values.unshift([cfg.dt]); //add Date
var transposedVal = [ //transpose values [[date,1,2,3]]
values.map(function(e) {
return e[0];
}),
];
target
.getRange(lastRow + 1, 2, transposedVal.length, transposedVal[0].length)
.setValues(transposedVal);
}
References:
Arrays
Array#Unshift
Array#map
Best Practices
DRY Principle