Using any array - arrays

Using google scripts in google sheets.I'm trying to use an arrary that has zip codes in it to look at a certain field and if that field matches one of the values in the array then it will proceed otherwise i'll keep going. I can't seems to figure that out. I'm having issues with the .indexOf function.
for (var i = 0; i < data.length; ++i) {
var tzip = new Array("02703", "02763", "02019", "01504", "02712", "02720");
var dzip = new Array("02721", "02722", "02723", "02724", "02035", "02038");
var row = data[i];
var emailAddress = row[18]; // First column
var message = "Hello"
var emailSent = row[19]; // Third column
var leadsent = row[20];
if (emailAddress == "Oil Sales" && tzip.indexOf(row[9] != 1) && emailSent != LEAD_SENT && leadsent != LEAD_COPIED) {
}
}

You had tzip.indexOf(row[9] != 1) where row[9] != 1 will evaluate to a Boolean value. This means that you will be searching tzip for the index of a Boolean value.
If you change that to
tzip.indexOf(row[9]) != 1
then the value of row[9] can be at any index in tzip except for index 1.
I think what you meant was
tzip.indexOf(row[9]) != -1
since the indexOf function returns the index -1 if the value row[9] is not contained in tzip.

Related

Apps Script - compare strings in two arrays

I am a stuck on this piece of code. I have an Example sheet with two tabs. The first tab is new items. A new item is comprised of two pieces, a attribute code (string), and an item ID (number). In the other tab "Locations" there are a bunch of empty locations. Each location has primary attribute (string), and a set of secondary attribute codes in a longer string.
I have assigned these two ranges to two unique arrays.
function matchcodes() {
var locss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Locations');
var lastlocRow = locss.getLastRow();
var newitems = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('New Items');
var lastNIRow = newitems.getLastRow();
var itemcodes = newitems.getRange("A1:B" + lastNIRow).getValues();
var locations = locationssheet.getRange("A2:D" + lastlocationRow).getValues();
Logger.log(itemcodes)
Logger.log(locations)}
What I am attempting to do is compare itemcodes[i][0] to locations[j][2] (match item attribute with location primary attribute). If the strings match I want to copy itemcodes[i][1] (ItemID) and set it as the value of locations[j][1]. If the strings do not match check the next iteration of locations[j][2].
If no matching attributes are found in locations[j][2], I would like to see if it is contained as a substring in locations[j][3] (starting back at the top and iterating through the whole list of secondary attributes. If the substring code is contained in loactions[j][3] I would like take the same action in the first IF condition.
Once a new item is matched, the loop can break, and the next item can be located itemcodes[i+1][0]. If no match is found in the primary or secondary search, also iterate to the next new item.
Where I'm struggling is writing the condition statements to compare both strings and substrings within strings.
//for (var i = 0; i < itemcodes.length; i++) {
//for (var j = 0; j < locations.length; j++) {
//if (itemcodes[i][0] == locations[j][2]) {
// I want set the value of locations[j][1] with itemcodes[i][1]
}
// if no match is found in entire [j][2] column, search for substring in locations[j][3] column
//if item match is found, or no match is found in all of [j][2] or [j][3] break loop and iterate to [i+1][0] and start the next loop
Input (3 iterations)
Results
Any help would be much appreciated. Or if you can point me to a similar thread. (I've not had any success finding a similar example) Thanks in advance!
Try:
function matchCodes() {
const newItems = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(`New Items`)
const locations = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(`Locations`)
const newItemsValues = newItems.getDataRange().getValues()
const locationsValues = locations.getDataRange().offset(1, 0).getValues()
newItemsValues.forEach(([attribute, id]) => {
const primaryTarget = locationsValues.findIndex(row => row[2] === attribute && row[1] === ``)
if (primaryTarget !== -1) return locationsValues[primaryTarget][1] = id
const secondaryTarget = locationsValues.findIndex(row => row[3].includes(attribute) && row[1] === ``)
if (secondaryTarget !== -1) return locationsValues[secondaryTarget][1] = id
})
locations.getDataRange().offset(1, 0).setValues(locationsValues)
}
Learn More:
Array.findIndex()
Destructuring Assignment

Loop through array and get row number for each element

I am quite new to Google Script, I'm learning on the job.
I have a range of data as a variable. It's only one column, column F in this case, but there are empty cells between values. I have a working script (got it from here earlier), which only loops through the cells with values in them. So lets say value1 is in F5, value2 is in F13, it's all random and always changing.
I'm trying to get the row number for these values, so that script should give back "5" for value1 and "13" for value2, ideally together with the value itself.
So far, that's what I have and I can not seem to progress further.
var sourceID = "sourceID";
var main = SpreadsheetApp.openById("mainID");
var mainsheet = main.getSheetByName("Lab Data");
var sourcesheet = source.getSheetByName("sheet name");
var dataRange = sourcesheet.getDataRange(); // range full sheet
var values = dataRange.getValues(); // values full sheet
var SWrowss = findCellForSW(); // getting start row from another function
var CQrowss = findCellForCQ(); // getting last row from another function
var noRows = CQrowss - SWrowss; // gets number of rows in range
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues(); // range we need, column F
// get rid of empty cells from range - copied script from stack overflow
var cResult = colss.reduce(function(ar, e) {
if (e[0]) ar.push(e[0])
return ar;
}, []);
Logger.log("cResult: " + cResult); // cResult contains all sub headers - no empty cells
// gets element's position in array
for(var b = 0; b < cResult.length; b++){
var position = b+1;
Logger.log("pos " + position);
} // end for
If you want to know the row number, I would propose you a different approach
Just loop through your values and retrieve the position of the ones that are not empty:
...
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rows = [];
var calues = [];
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
var row = SWrowss+b+1;
rows.push(row);
var value = colss[b][0];
values.push(value);
}
}
...
With the other solution you can build a single object that can do the conversion for you very quickly.
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rvObj={};
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
rvObj[colss[b][0]]=SWrowss+b+1;
}
}
With rvObj now you can get any row with var row = rvObj[value];

Push every new match from regEx in array

I try to parse some xml file, with this code:
function parseXml() {
var url = 'http://www.inpo.ru/documents/pricelists/pricelist.xml';
var xml = UrlFetchApp.fetch(url).getContentText();
var parseregexp = new RegExp (/.*em><no>(\d+)<\/no><title>(.+?)<\/title><price vat="\w+">(\d+.\d+|\d+)<\/price><unit>(.+?)<\/unit><free>(\d+)<\/free>(.|\s)*?<it/g)
var parsedData = '$1 $2 $3 $4 $5 '
var rangeRegex = [];
var Pdata = xml.replace(parseregexp,parsedData)
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
ss.getRange(1, 1).setValue(Pdata)
}
And here is xml fragment:
<item><no>48514</no><title>The workpiece is the rod d 8x150mm P6AM5 HRC 64-66" CNIC"</title><price vat="yes">154.58</price><unit>Pcs</unit><free>59</free><remarks>Used to make an axial tool.
Hardness HRC64-66</remarks><img thumbnail="http://www.inpo.ru/index/I:48528/THUMBNAIL:0.jpg">http://www.inpo.ru/index/I: 48528 / PREVIEW: 0.jpg</img></item><item><no>48515</no><title>The workpiece is the rod d 8x200mm P6AM5 HRC 64-66"CNIC"</title><price vat="Yes">198.24</price><unit>pcs</unit><free>32</free><remarks>Used to make an axial tool.
Hardness HRC64-66</remarks><img thumbnail="http://www.inpo.ru/index/I:48528/THUMBNAIL:0.jpg">http://www.inpo.ru/index/I: 48528 / PREVIEW: 0.jpg</img></item>
And result in Pdata is:
48514 The workpiece is the rod d 8x150mm P6AM5 HRC 64-66" CNIC" 154.58 Pcs 59 48515 The workpiece is the rod d 8x200mm P6AM5 HRC 64-66"CNIC" 198.24 pcs 32
In this example in Pdata I have 1 long string from all regex matches. How I can make an array with 5 columns from all matches? I think to push every match to array with "for" cycle, but dont know how it's mades. Would be pleasefull for any help
Alternate Solution:
Since you are trying to access xml data you can use XMLservice.parser
However there seems to a problem in the fetch call, I was unable to get the whole data (fetch gives a truncated file, perhaps it is timing out, 16mb file) , so I downloaded the data file and uploaded it into google drive.
This file could be used to parse XML data like so:
function parseXml() {
var file = DriveApp.getFileById("Xml File ID") //Get the id of the uploaded file and replace it for "Xml File ID"
var xml = file.getBlob().getDataAsString()
// The below code gave a error for XML parser
/*var url = 'http://www.inpo.ru/documents/pricelists/pricelist.xml';
var options = {
'method' : 'get',
'contentType': 'application/xml',
}
var xml = UrlFetchApp.fetch(url,options).getBlob().getDataAsString()
Logger.log(xml)*/
// End of code with gave an error
var arrayItems = []
var XmlElem = ["no","title","price","unit","free"] //Elements to look for
var document = XmlService.parse(xml);
var RCounter = 0
var groups = document.getRootElement().getChildren(); //GetGroup Element
for(var k = 0; k< groups.length; k++){ // Loop through each group element
var main = groups[k].getChildren() // Get sub groups in each group
for (var j=0 ; j < main.length; j++){ // Loop through each subGroups
var mainChilds = main[j].getChildren() //Get items in each subGroups
for (var l = 0 ; l < mainChilds.length; l++){ // Loop through each items
var items = mainChilds[l].getChildren(); // Get elemetns like "no","title","price","units","free" in each item
arrayItems[RCounter] = []
var total = 0;
for (var i = 0; i < items.length; i++) {
// Logger.log(items[i].getName())
var index = XmlElem.indexOf(items[i].getName()) //Look for items and place the value at corresponding index
if(index != -1)
arrayItems[RCounter][index] = items[i].getValue()
} //End Loope for elements
if(arrayItems[RCounter].length > 0) //in case the array is empty, reuse it
RCounter++
} // End loop for items
} // End loop for sub Groups
} // End loop for Groups
Logger.log(arrayItems)
}
Hope that helps!

Improve function delete rows by contain value

I have working code, that delete row from sheet if column corresponds to one of the conditions. It based on arrays and because of it works much more faster than standard google sheet deleteRow function. I call it like this:
deleteRowsBV('SIZ',4,'0','')
where
deleteRowsBV(listName,ColNum,FirstSearch,SecondSearch)
What I want is a call function with more or less and equal signs, like this:
deleteRowsBV('SIZ',4,<='0',=='')
But in case of my main function, it doesn't work, when I specify a variable instead of a sign and a value.
Here is main function:
function deleteRowsBV(listName,ColNum,FirstSearch,SecondSearch) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(listName);
var DataLengBefore = sheet.getLastRow();
var DataColLeng = sheet.getLastColumn();
var data = sheet.getRange(1,1,DataLengBefore,DataColLeng).getValues();
for (var i = data.length-1; i >= 0; i--) {
if (data[i][ColNum] <= FirstSearch||data[i][ColNum] == SecondSearch) {
data.splice(i, 1);
}
}
sheet.getRange(10, 1, DataLengBefore,DataColLeng).clearContent();
sheet.getRange(10, 1,data.length,5).setValues(data);
}
Based from this related post, spreadsheet rows and columns are numbered starting at 1, for all methods in the SpreadsheetApp, while javascript arrays start numbering from 0. You need to adjust between those numeric bases when working with both. When deleting rows, the size of the spreadsheet dataRange will get smaller; you did take that into account, but because you're looping up to the maximum size, the code is complicated by this requirement. You can simplify things by looping down from the maximum.
You may refer with this thread. However, this only looks at the value from a single cell edit now and not the values in the whole sheet.
function onEdit(e) {
//Logger.log(JSON.stringify(e));
//{"source":{},"range":{"rowStart":1,"rowEnd":1,"columnEnd":1,"columnStart":1},"value":"1","user":{"email":"","nickname":""},"authMode":{}}
try {
var ss = e.source; // Just pull the spreadsheet object from the one already being passed to onEdit
var s = ss.getActiveSheet();
// Conditions are by sheet and a single cell in a certain column
if (s.getName() == 'Sheet1' && // change to your own
e.range.columnStart == 3 && e.range.columnEnd == 3 && // only look at edits happening in col C which is 3
e.range.rowStart == e.range.rowEnd ) { // only look at single row edits which will equal a single cell
checkCellValue(e);
}
} catch (error) { Logger.log(error); }
};
function checkCellValue(e) {
if ( !e.value || e.value == 0) { // Delete if value is zero or empty
e.source.getActiveSheet().deleteRow(e.range.rowStart);
}
}

for loop not iterating over last element of 2D array in google app script (GAS)

I am working on a script that, in part, takes an array of names, compares each name to column A in a sheet, and returns with a row matched value in column B. (Like the vLookup command in sheets)
The setup
var ss = SpreadsheetApp.getActiveSpreadsheet();
var clientsSheet = ss.getSheetByName("Clients");
var cRow = clientsSheet.getLastRow();
var cColumn=clientsSheet.getLastColumn();
var cData=clientsSheet.getRange(1,1,cRow,cColumn).getValues(); //create array of client data
The trouble code
//put each client on their own row and add hour
for(i=0; i < client.length; ++i){
var cl = client[i]
//iterate over array of clients (column A) and hours (Column B) to find match and log the number in column B
for(j=0;j<cData.length;++j){
if (cData[j][0]==cl){
var hour = cData[j][1];
}
}
//return the matched values
Logger.log(cl+" - "+hour);
}
The var 'client' is an array that was split from a list of names in a single cell that are separated by commas (see whole code below)
At the moment it works great except that it misses the last element in the array.
for example:
if I have a sheet with two columns and three rows like so:
A 1
B 2
C 3
I would get back
A-1
B-2
C-
It is missing that last piece on the last element - it should be
A-1
B-2
C-3
I am stumped, and I know that it must be some simple little thing.
Any help would be amazing
Thanks!
The Code:
function logClients()
/*
Take data from a google form check box submissions. Check box submissions put all checked answers into a single cell separated by a comma. The function first takes the most recently submitted row, removes unneeded spaces, and splits each element into its own part of an array.
Then, the function compares each clients name in the array to a sheet with other info, such as the default number of hours we meet. It takes the clients name, the date of submission, and the hours, and logs them on a new row in two different sheets, the Hours sheet and the Trans Log sheet.
*/
var ss = SpreadsheetApp.getActiveSpreadsheet();
var logSheet = ss.getSheetByName("Log"); //Raw data from the Google form
var hourSheet = ss.getSheetByName("Hours"); //logged data for my records, separated into individual clients
var transLog = ss.getSheetByName("Trans Log"); // logged data minus "other" catagory
var clientsSheet = ss.getSheetByName("Clients"); //sheet containing all clients names and the typical hours we meet
var lRow = logSheet.getLastRow();
var hRow = hourSheet.getLastRow();
var tRow = transLog.getLastRow();
var cRow = clientsSheet.getLastRow();
var cColumn = clientsSheet.getLastColumn();
var cData = clientsSheet.getRange(1, 1, cRow, cColumn).getValues();
//get list of clients from cell and split it into an array
var Client = logSheet.getRange(lRow, 2).getValue().replace(", ", ","); //remove all spaces after a comma
var client = Client.split(",");
//get "other" information and do the same
var Other = logSheet.getRange(lRow, 5).getValue().replace(", ", ",");
var other = Other.split(",");
//check the date and set to today if nothing else has been entered
var dcell = logSheet.getRange(lRow, 4).getValue();
var date = new Date()
if (dcell == "") {} else if (dcell == "Yesterday") {
date = new Date(date.getTime() - 1 * (24 * 3600 * 1000));
} else {
date = dcell
}
var date = Utilities.formatDate(date, "GMT-8", "MM/dd/yy"); //format date
//put each client on their own row
for (i = 0; i < client.length; ++i) {
var cl = client[i]
var hour = logSheet.getRange(lRow, 3).getValue(); //hours
if (hour == !"") {
break;
}
for (j = 0; j < cData.length; ++j) {
if (cData[j][0] == cl) {
var hour = cData[j][1];
}
}
Logger.log(date + " - " + cl + " - " + hour);
hourSheet.appendRow([date,cl, hour]);
transLog.appendRow([date, cl, hour]);
}
//put each client on their own row
for (i = 0; i < other.length; i++) {
hourSheet.appendRow([date, other[i], getHour(client[i])]);
}
} //end of function
``
This is a code that I have been working on to teach myself Java and Apps-script
Yup, simple mistake.
Not all of the spaces before each name were being removed from the array, so the if statement would skip right over them because they were not a true match

Resources