Im putting together a pretty lengthy spreadsheet in google spreadsheets. This spreadsheet contains information about products ie name, brand, part number, ect... I was helped previously and given some nice solutions but I am still running into limitations.
What I am trying to do is generate, automatically, a description field based on information in other cells.
The formula I am using in the descriptions column is ="Brand Name"&" "&A3&" "&B3&" "&(joinVals(E3:G3," x "))&" "&K3
joinVals(E3:G3," x ") is joining together separate columns containing Length(E) Width(F) Height(G) and adding 'x' between the values. That results in E x F x G
This Script does work for the above formula
function joinVals( rangeValues, separator ) {
function notBlank(element) {return element != '';}
return rangeValues[0].filter(notBlank).join(separator);
}
However I keep getting this error
Script invoked too many times per second for this Google user account.
I am wondering If I can do this as an array to avoid the error as this doc contains 1000+ ROWS.
When all is said and done my result I would like to achieve should be something like this
"Brand Name" Part Number(A) Product Name(B) Dimensions(E x F x G) Size(K)
Should I be running an ARRAY Script?
Thank you all so much, this forum has been such a help!
It is possible to use an Array solution, but you'd have to change a lot how you use formulas in your spreadsheet. The easiest solution is to use built-in spreadsheet formulas directly. There's no need for a custom Apps Script formula for this.
="Brand Name"&" "&A3&" "&B3&" "&(join(" x ";filter(E3:G3;E3:G3<>"")))&" "&K3
As shown by AdamL in the comments, here's an ArrayFormula solution that uses only built-in formulas.
=ArrayFormula(IF(LEN(A3:A),REGEXREPLACE("Brand Name "&A3:A&" "&B3:B&" "&REPT(E3:E&" x ",E3:E<>"")&REPT(F3:F&" x ",F3:F<>"")&REPT(G3:G&" x ",G3:G<>"")&CHAR(9)&" "&K3:K,"( x \t)|\t",""),))
As I said, such ArrayFormula style of solution can be used when writing custom Apps Script as well. I just don't think that's worth it when there's (arguably) simpler built-in solutions (but surely faster and way larger quotas).
Related
I'm trying to convert order form data submitted from a Squarespace website from the following format to a table with 4 columns:
Store,Item,Quantity,Details;Store2,Item2,Quantity2,Details2; (etc...)
Commas separate columns while semi-colons separate rows.
All the methods I've tried so far have been successful in splitting the data into the desired form, but the problem occurs when new data is added. When the form is submitted, it creates a new row in the next available empty row. I can't seem to find a way to automate the process without receiving cyclical dependency errors, since each order can have any amount of item entries.
Example spreadsheet:
https://docs.google.com/spreadsheets/d/1ZEWtmMiWO0Us76Z7o7GB7Salw1Rl_-1PhK6GzeOD0GM/edit?usp=sharing
The above example splits the data as desired. I cannot figure out how to make it work with the data added as a new row. I would also like to continue using sheets for its cloud functionality.
Any advice is appreciated, including entirely new ways of processing the data, whether with a script, a different remotely accessible order processing app compatible with Squarespace forms, or natively within Sheets.
You want to achieve the following conversion.
Sample formula:
=ARRAYFORMULA(SPLIT(TRANSPOSE(split(A4,";")),","))
In this formula, the cell "A4" has the input value.
You have already used the formula of =TRANSPOSE(split(A10,";")). In this answer, I used this.
For TRANSPOSE(split(A10,";")), the value is splitted with , using SPLIT and ARRAYFORMULA.
Result:
Sample script:
When you want to use Google Apps Script, you can also use the following script.
function myFunction(value) {
const values = value.split(";");
return values.splice(0, values.length - 1).map(e => e.split(",").map(f => isNaN(f) ? f : Number(f)));
}
In this case, please copy and paste the script to the script editor, and put the custom function of =myFunction(A4) to a cell.
The same result with above formula can be obtained.
References:
SPLIT
ARRAYFORMULA
split()
map()
I'm using Google App Script. I have a spreadsheet with questions on it for energy auditors about buildings they visit. The auditor is asked to put their answers to the spreadsheet's questions in certain cells. Then they can use a script I wrote to generate a more formal looking Google Document report. The report is generated via these steps: Each cell the auditor inputs an answer into is a defined range. For instance, let's say Cell B10 is defined as "buildingAddress" in spreadsheet. The auditor is asked to put the building address in that cell - let's say he inputs "55 Sample Drive, Portland". When the auditor clicks to generate a Document report, the script runs these lines:
var buildingAddress = sheet.getRangeByName('buildingAddress').getValue();
copyBody.replaceText("<buildingAddress>", buildingAddress);
The place holder in my (Document file) report template is <buildingAddress>. So the code finds this in the report template and replaces it with "55 Sample Drive, Portland" - the value the auditor entered into the spreadsheet cell.
Unfortunately, there are A LOT of such cell values I need to pull from the spreadsheet and push to a placeholder in the report document. They all fit the structure of this:
var buildingAddress = sheet.getRangeByName('buildingAddress').getValue();
copyBody.replaceText("<buildingAddress>", buildingAddress);
So, I'm wondering, can I achieve the same result but use a lot less code by using an array and for loop??? Let's say the array looks like this:
var array = ["buildingAddress", "buildingOwner", "auditorName"];
How do I set up a for loop???
Thank you!!!!!
a loop will not give you gains its exactly the same except cleaner code.
debug it and see where the slow parts are (see execution transcript or log at key steps).
For example if its slow to get a range by name, and all those named ranges are contiguous, instead make a single named range for those cells. get the range (will return array) and get the values from there. this makes a single "get range" call instead of the N you have now.
from your "how to write a loop" question, seems you are just beginning programming. Id suggest a tutorial and more practicing as stackoverflow assumes you know those basics.
Thanks! If anyone's interested, here's what worked for me. I made an array of string objects. Each string was same text as a defined range in my spreadsheet. Then I used this for loop:
for(var i = 0; i < simpleCopyReplaceArray.length; i++){
var definedRangeCellName = simpleCopyReplaceArray[i];
var cellValue = ss.getRangeByName(definedRangeCellName).getValue();
var placeHolder = "<" + definedRangeCellName + ">";
if( cellValue != ""){
copyBody.replaceText(placeHolder, cellValue);
}else{
copyBody.replaceText(placeHolder, "");}
}
I am having a little problem with xpath in seleniumdriver.
I would like an xpath locator to narrow down its selection via two variables using exact matching at different points of the node hiearchy. This part is done.
You may imagine my case as addressing a two dimensional array in the xml with xPath, with each dimension being given as the two variables I have in it(they are standard text searches via js variables, not xpath variables).
What I'm struggling with is the resulting construction does not tell the difference between the elements of the first dimension, so as long as the given variable value is one of the dimensions, it will address every element in the second dimension fine. I can not assume they are unique or they are in any order. I am using it for testing so this is not acceptable.
How can I form an expression that will not doesn't do the same mistake?
I have tried the 'and' expression but both selenium and xpath tools say the value is '1' for 'found' but it doesn't give me a node locator to work with.
Example, my structure looks similar, so addressing it properly by x1/y1 for example looks fine.
//x1//y1
//x1//y2
//x2//y3
//x2//y4
//x3//y5
//x3//y6
Should work, works ok.
//x1x//y1
//x1x//y2
//x2x//y3
//x2x//y4
//x3x//y5
//x3x//y6
(Giving nonexistent input as 1st dimension.) My input is not fault tolerant, I look for exact value so the tests fail here as they should.
//x2//y1
//x2//y2
//x3//y3
//x3//y4
//x1//y5
//x1//y6
DING, the locator finds y values here when it should not(the y vales are on different leaves of the node tree). I need help with this.
Here is the locator in question:
return element(by.xpath(".//div[#name='typeList']//div[.//text()='" + moduleName + "']//div[./text()='" + typeName + "']")).getText();
TypeList is the name of the owner element, it does not make any differnece if I remove it, but please keep it in mind when giving me examples.
In the end, it was indeed a syntactical problem, before the text keywords.
I was trying this
//div[./text()='Zero']//div[./text()='Number']
Instead, I needed something like this.
//div[.//text()='Zero']/div[.//text()='Number']
Apparently the first one does looks for 'Number' regardless the value of the first constraint as long as every is defined in my file(does not have to be in its upward xnode path.)
As a final note, I advise against using the chrome xpath helper as its behavior is near random, it gives different results after deleting and replacing the same expression. Ugh. The only other one for chrome is adware... I figured my result out by trial and error with the firefox xpath checker tool.
1, I ended up needing to additionally add an node upwards for the element for angular select ui tool(we use selectize.js, a searchable select box), else it was confused what to return, but this is unrelated to the original question as I tried that before with the original expression.
2, I also had to add a node between the first and second text search, else it would look for the second expression in the first one too, eg. looking for Number in Zero, and treat it like a valid value if found. The problem still occurs the other way around, this can be fixed too by applying additional type/name constraints in the first one(not in final example to save space).
So this is what I ended up with:
.//div[#name='typeList']//div/div[.//text()='Zero']/div/div/div[.//text()='Number']
This question builds off a previous question that I asked:
How do I remove the first character of a string and treat the remaining values as an integer in BigQuery
I am having trouble getting a regular expression that I need for some client work to function. Basically, I want to look through all the cells in a column which has the following types of entries:
customer-o400744190
o400748216
o455239157-new-customer
other similar types with o4552334214 somewhere in the cell
and use something like REGEX_EXTRACT() to parse out or extract "oXXXXXXXXX" from every cell & dump those values into a new column. The data in the column I am pulling from is stored in a string, and can stay that way. Does anyone have any suggestions?
I worked around the problem by just using:
RIGHT(hits_transaction_transactionId, 10)
but know that I am only getting some of the cases that apply. Thus, this is not an acceptable long term solution. Any ideas are greatly appreciated.
Depending on how your data universe is, you could go with /o[0-9]+/
so you would be extracting any ocurrences of o and then at least one number
I am trying to create a custom method in Google Spreadsheet. I have the following method to replace the missing WEEKNUM method. (I leave to second parameter in order to allow upload of excel files.)
function WEEKNUM(inDate, dummy){
return Utilities.formatDate(inDate, "GMT", "w");
}
I call in method in approximately 400 rows twice (800 times) in one spreadsheet. Some of the formulas complete however for other I get this error message.
error: There are too many scripts running simultaneously for this Google user account.
Is there anything I can do to fix this? I understand 800 executions it a lot but not anymore than would be expected of built in functions. I know there are alternative ways to calculate the week number (such as =LEFT(TEXT(A2; "w d"); 2)) however I want to know if it is even possible to create custom formula functions that wont be subjected to this invisible ceiling.
Thank you in advanced for your replies.
Have you custom function receive a range and output an array. No need to use an arrayformula, which also wont work on a custom function
Have you tried an ArrayFormula? In your spreadsheet, instead of having 800 calls to:
=WEEKNUM(-cell-, -dummy-)
in cells A1 to B400, try:
=ARRAYFORMULA(WEEKNUM(A1:B400, -dummy-))
in cell A1.