I'm having trouble matching a string in an array. Column B2:Lastrow is defined as array which is "ID". I am trying to paste only unique entries to google sheet which aren't available in Column B2:Lastrow. Issue is..when I run the code it allows duplicates in the google sheet as well.
I was using it through count formula on the sheet but that leads to maximum code runtime error..hence I'm using the range as an array. Solves the error but not able to recognize if the string is unique.
// Code: List Gmail Label to Google Sheet and save attachment to GDrive
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName('Summary');
var label = GmailApp.getUserLabelByName("Caterpiller Account");
var threads = label.getThreads();
function getEmails() {
for (var i = 0; i < threads.length; i++) {
var row = sheet.getLastRow() + 1;
var message = threads[i].getMessages()[0];
var ID = message.getId();
var fulldata = sheet.getRange('B2:B' + row).getValues();
if (fulldata.indexOf(ID) == -1) {
var messages=threads[i].getMessages();
var listID=threads[i].getPermalink();
var listdate=threads[i].getLastMessageDate();
var message = threads[i].getMessages()[0];
var attachment = message.getAttachments();
var attachmentBlob = message.getAttachments()[0].copyBlob();
var folder = DriveApp.getFolderById("1ilsecZOexqTWGfAMu5xJDx1pKh3z1US-");
// EXTRACTOR CODE:
for (var m=0; m < messages.length; m++) {
sheet.getRange(row,1).setValue(messages[m].getSubject());
sheet.getRange(row,2).setValue(ID);
sheet.getRange(row,3).setValue(listdate); // Value - Date
for (var z=0; z<attachment.length; z++) {
var file = DriveApp.getFolderById("1ilsecZOexqTWGfAMu5xJDx1pKh3z1US-").createFile(attachmentBlob);
//Pending: Weblinkview (basically get permanent url of file) / Or self developed function that gets file through description (where description is email ID)
}
row++;
}
}
}
}
Expected: Unique entries & a faster Code runtime.
Actual: I'm crap & code time is still the same.
bool IsSame(string str,char arr[100])
{
if(str.lenght!=strlen(arr))return false;
for(int i=0;i<str.lenght;i++)
{
if(str[i]!=arr[i]) return false;
}
return true;
}
Related
I am trying to create a google script that will scan through a specific column of one google sheet and check if any new additions are a duplicate. I have come up with the following, but it isn't working.
function hasDuplicates() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Customer and form Details");
var array = sheet.getRange('B2:B' + lastRow).getValues();
var valuesSoFar = [];
for (var i = 0; i < array.length; ++i) {
var value = array[i];
if (value in valuesSoFar) {
SpreadsheetApp.getUi().alert('Hello, world!');
}
else{
valuesSoFar.push(value);
}
}
}
As far as Im aware the above code creates an array called array and populates it with the specific range I am interested in. I then create a new, empty, array called valuesSoFar. The code then loops through the column and sequentially checks if that item has already been seen before, if so it gives you an alert. If not it adds it to the list of new items and keeps going.
It looks a bit like you are using the online documentation code.
But the following assignment is missing:
var lastRow = sheet.getLastRow();
or just replace lastRow with sheet.getLastRow()
Update:
I assume that the following solution should work if you actually have any duplicates in your column B:
function hasDuplicates() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Customer and form Details");
var array = sheet.getRange('B2:B' + sheet.getLastRow()).getValues();
var valuesSoFar = [];
for (var i = 0; i < array.length; ++i) {
var value = array[i][0];
if (value in valuesSoFar) {
SpreadsheetApp.getUi().alert('Hello, world!');
} else {
valuesSoFar.push(value);
}
}
}
If it isn't working yet, I am sorry.
As long as you can not provide any information on what kind of error you are running into, I will not look into this anymore.
I'm trying to extract numbers such as the ones listed below from my Gmail messages using Google Apps Script.
2,495.00
1,594
3,777.23
642.00
This is the code:
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var threads = GmailApp.search('subject:(Transaction) after:2016/7/31 before:2016/8/10');
for (var i=0; i<threads.length; i++)
{
var messages = threads[i].getMessages();
var tmp;
for (var j=0; j<messages.length; j++)
{
var content = messages[j].getBody();
var subject = messages[j].getSubject();
var date = messages[j].getDate();
Logger.log(content);
if (content)
{
tmp = content.match(/\d+(,\d+)*(\.\d+(e\d+)?)?/);
var number = (tmp && tmp[j]) ? tmp[j] : 'No number';
sheet.appendRow([number, subject, date]);
}
else
{
sheet.appendRow([content, subject, date]);
}
}
}
}
I've been getting mixed results. For some messages this works as intended but for some it completely skips the numbers from the messages. I'm a newbie to JS/GAS and I thought the problem was in the regex but I'm not sure. Any help in this would be appreciated.
you are facing two trouble here:
the regex you are using don't look optimised (but neither what you are looking is clear a number like 1,594 should not be found if you are also looking at number that look like that 642.00). Nevertheless you could use a a regex like Shekhar Khairnar proposed in comment or something similar (the gat the end is important as there is more than one number in your mail).
The second trouble is in the line var number = (tmp && tmp[j]) ? tmp[j] : 'No number';. Why is there a jvar in this line? jis reference to the for loop --> number of messages, nothing to do with the occurences in your message.
What I can propose you is something like that:
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var threads = GmailApp.search('test');
var re = /(?:\d{1,3}[,])*\d{1,3}\.{0,1}\d{1,3}/g;
for (var i=0; i<threads.length && i<5; i++) // added a condition because I didn't wanted to have too many results
{
var messages = threads[i].getMessages();
var tmp;
for (var j=0; j<messages.length; j++)
{
var content = messages[j].getPlainBody(); //.getBody();
var subject = messages[j].getSubject();
var date = messages[j].getDate();
//Logger.log(content);
if (content)
{
tmp = content.match(re); // /\d+(,\d+)*(\.\d+(e\d+)?)?/);
var number = tmp || ['No number']; // result of tmp is either null or an array --> if it's null then it will take the value 'no number'
Logger.log(number);
sheet.appendRow([number.join(" | "), subject, date]);
}
else
{
sheet.appendRow([content, subject, date]);
}
}
}
}
Using the google simple mail merge (https://developers.google.com/apps-script/articles/mail_merge) I have tried and tried but cannot work out a way to email just the last row, rather than emailing for every row when the script is run.
Any help much appreciated!
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheets()[0];
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, 4);
var templateSheet = ss.getSheets()[1];
var emailTemplate = templateSheet.getRange("A1").getValue();
// Create one JavaScript object per row of data.
var objects = getRowsData(dataSheet, dataRange);
// For every row object, create a personalized email from a template and send
// it to the appropriate person.
for (var i = 0; i < objects.length; ++i) {
// Get a row object
var rowData = objects[i];
// Generate a personalized email.
// Given a template string, replace markers (for instance ${"First Name"}) with
// the corresponding value in a row object (for instance rowData.firstName).
var emailText = fillInTemplateFromObject(emailTemplate, rowData);
var emailSubject = "Tutorial: Simple Mail Merge";
MailApp.sendEmail(rowData.emailAddress, emailSubject, emailText);
}
}
FIXED: In case any one is ever interested:
Change:
var rowData = objects[i]
to:
var rowData = objects[objects.length-1];
and:
for var (i = 0; i < objects,length; ++i) {
to just:
var i = 0; i < objects,length; ++i;
I'm attempting to grab the values from a data range, loop over the data, match a value in that data, then based on a matching value, update cell located a few columns over.
I'm able to locate value to match, but I'm having a hard time understanding how to update the cell a few columns over. Below is the code I've gotten so far minus the .setValue piece.
var trackingSS = 'Spreadsheet 1';
var decisionSS = 'Spreadsheet 2';
function grabRequestID() {
var ss = SpreadsheetApp.openById(decissionSS);
var range = ss.getActiveSheet().getRange(ss.getLastRow(), 2, 1, 1)
var requestID = range.getValue();
return requestID;
}
function managersDecision() {
var ss = SpreadsheetApp.openById(trackingSS)
var sheet = ss.getSheetByName('Requests');
var data = sheet.getDataRange().getValues();
var requestID = grabRequestID();
for (var i=0; i < data.length; i++) {
for (var j=0; j < data[i].length; j++) {
if (data[i][j] == requestID) {
Logger.log('found it');
}
}
}
}
As you can see there are two functions. managersDecision() reads in all the data from spreadsheet 1. It then calls grabRequestID() and uses this value (from spreadsheet 2) as the matching criteria as it loops over the data from spreadsheet 1. Currently it will locate and find the match.
What I want to have happen now, is based on the match, go over two columns in the same row and update the cell value to "approved" or "denied" based on successfully finding a match.
I'm a bit lost on how to get it to write to the cell. Should I try and identify the row its in and then work to set the value? Maybe grab the entire row the match is in (into an array) and then rewrite the row?
Any assistance would be appreciated..
To set a value you just need to take in count that you are working with an array that start at zero, but in the spreadsheet we start counting at one. You'll also need to be sure that you are trying to write in an existing cell. So prior writing, add the necessary column.
I didn't wrote the "denied" part as it was going through all the cell of the spreadsheet, but I wrote a second version of the managersDecision function where I only go through one column and here I took care of that denied part.
here the code:
var trackingSS = 'Spreadsheet1';
var decisionSS = 'Spreadsheet2';
function grabRequestID() {
var ss = SpreadsheetApp.openById(decisionSS);
var range = ss.getActiveSheet().getRange(ss.getLastRow(), 2, 1, 1)
var requestID = range.getValue();
Logger.log("requestID= "+requestID);
return requestID;
}
function managersDecision() {
var ss = SpreadsheetApp.openById(trackingSS)
var sheet = ss.getSheetByName('Requests');
var data = sheet.getDataRange().getValues();
var requestID = grabRequestID();
for (var i=0; i < data.length; i++) { // going through all the rows
for (var j=0; j < data[i].length; j++) { // this is going through all the cell of a row
if (data[i][j] == requestID) {
Logger.log('found it');
var row = Number(i)+1;
var col = Number(j)+1+2;
while(sheet.getMaxColumns()<col){
sheet.insertColumnsAfter(sheet.getMaxColumns(),col-sheet.getMaxColumns());
}
sheet.getRange(row, col).setValue("approved");
}
}
}
}
function managersDecision2() {
var ss = SpreadsheetApp.openById(trackingSS)
var sheet = ss.getSheetByName('Requests');
var data = sheet.getRange("A:A").getValues()
var requestID = grabRequestID();
var col = 1+2;
while(sheet.getMaxColumns()<col){
sheet.insertColumnsAfter(sheet.getMaxColumns(),col-sheet.getMaxColumns());
}
for (var i=0; i < data.length; i++) { // going through all the rows
var row = 1+i;
if (data[i][0] == requestID) {
Logger.log('found it');
sheet.getRange(row, col).setValue("approved");
}
else if(data[i][0] !=""){
Logger.log(row)
sheet.getRange(row, col).setValue("denied");
}
}
}
I am trying to make a script that will create a table from a spreadsheet with a list of suppliers. The spreadsheet has over a thousand entries, so my script is processing it very slowly. Here is the code
function SupplerAnalysis() {
//Importing data
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
//Creating a sheet
if (ss.getSheetByName("Analysis") !=null) {
//Logger.log('exists');
} else {
//Logger.log('Creating new');
ss.insertSheet("Analysis");
}
var sheetNumber = ss.getSheetByName("Analysis").getIndex() - 1;
ss.getSheetByName("Analysis").clear();
var newsheet = ss.getSheets()[sheetNumber];
var newdata = newsheet.getDataRange().getValues();
newsheet.getRange(1, 1).setValue('Suppliers');
//Get list of suppliers
for (var s = 1; s < data.length; s++) {
var supplier = data[s][3];
var z = 1;
newdata = newsheet.getDataRange().getValues();
for (var r = 1; r < newdata.length;r++) {
if (supplier === newdata[r][0]) {
z = 2;
} else { Logger.log(r);}
}
if (z === 1) {
newsheet.getRange(r+1, 1).setValue(supplier);
} else if ( z > 1 ) { Logge.log('Error');
}
}
Column data[s][3] is the list of suppliers for different jobs. There are more than thousand entries, and about 160 suppliers in total. This script takes about 5 minutes to execute, which is very slow and ineffective.
How can I change the code to speed up this process?
Is there any way to get the output from the NewCategoryFilter in to a table?
Just don't call the API in loops:
function SupplerAnalysis() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var newsheet;
if ((newsheet=ss.getSheetByName("Analysis")) == null)
newsheet = ss.insertSheet("Analysis");
else newsheet.clear();
var supplierList = [['Suppliers']];
for (var s = 1; s < data.length; s++) {
for (var r = 1; r < supplierList.length; r++)
if (data[s][3] == supplierList[r][0]) break;
if (r == supplierList.length) supplierList.push([data[s][3]]);
}
newsheet.getRange(1,1,supplierList.length,1).setValues(supplierList);
}
Keep your eyes open on typos - I just typed this in.
Converting suppliers in object keys could be somewhat risky as the supplier names maybe are not legal object keys.
Getting rid of the call to newsheet.getDataRange inside your loop will probably speed things up. You can check for duplicates faster by storing values as object {} keys and using the "in" operator to see if they are present. e.g.
var set = {};
vals.forEach(function(value){
if(value in set) {
console.log('duplicate found');
}
set[value] = true;
});
I'm not sure what NewCategoryFilter is.