I want to create a Custom Function in my google sheet, which will take few inputs and compare them below is the example please:
I know this is very simple but when I try to save this code this give me the below error.
Missing ; before statement. (line 6, file "Code")Dismiss
Your function can be written in plain JavaScript for Google Apps Script:
function testFunction(A1,B1,C1) {
// check if all the three conditions are met
if (A1 == "Lion" && B1 == "Cheeta" && C1 == 1) {
// if they're met, return Cat_Family_Exists
return "Cat_Family_Exists"; }
// else return Cheeta
else {
return "Cheeta";
};
};
However, if you want to directly get the data out of a sheet, you might want to have a look at the docs.
Related
==================================
UPDATE 11 December 2019
My Question is more about Macro Script
The GOAL (in illustration)
to change below raw sheet:
to more readable format:
Basically what i'm doing is split the campaign name with the separator and parse it.
I don't have the problem if the function on only process single cell,for example:
on "Report" Sheet the CELL B2 , is taking data from "Data" B2 ONLY
i got problem when the return data require conditional operator that involve specific condition. So while processing cell B2, it require content from E2, D2, etc
=====================================
i'm taking data from Google Ads/Analytics API to Google Sheet on specific worksheet (i call it 'Raw Data').
Now i'm using pattern for the campaign, so i can easily split/break with separator in order for me to get specific data.
For Example:
With this, by using underscore as separator, i can split campaign name, into various data:
Campaign Objective: Sales
Campaign Title: TBMB
Network: SEM
Branch: All
Targeting: Keywords
..etc
Then i create new sheet called Called CReport which consist the same data from Raw Data sheet, but in much better visualization for marketing people.
Now, after searching on Google, i found the solution for self reference cell.
The script goes like this:
function getSegment(data,index){
temp=data.split("_");
return temp[index-1];
}
function dataParse(input,dataSegment){
return Array.isArray(input) ? input.map(function(e){
return e.map(function(f){
if(f!=""){
return getSegment(f,dataSegment);
}
}
)}
) : "false usage";
}
So if i want to have a column with Network Name, i can place this formula on row 2 (because row 1 is for table header) something like this:
=ArrayFormula(dataParse('RAW DATA'!B2:B;2))
Now my question:
This works for self-reference cell, means if the data taken from B2 in RAW DATA sheet, it will be the only data referenced to cell in Campaign Report sheet.
If the pointer is in B2 on CReport Sheet require data not only from B2 in RAW DATA but also D2 Cell.
What script i need to add in my function ?
i'm expecting the chunk of code will something like this
function dataParse(input,dataSegment){
return Array.isArray(input) ? input.map(function(e){
return e.map(function(f){
if(f!=""){
segmentData=getSegment(f,dataSegment);
if(segmentData=="google"){
returnData=get reference from column D //<---
}else{
returnData=get reference from column E //<---
}
return returnData
}
}
)}
) : "false usage";
}
Hope its clear enough.
Thanks in Advance !
I modified your function in this way:
// range (String): It will be used to get the info in a range
function dataParse(input,dataSegment, range){
var val = "";
return Array.isArray(input) ? input.map(function(e, index){
return e.map(function(f){
if(f!=""){
// If col D has value google then take info from col B
if(f === "google") val = getDesiredRangeValue("B", range, index);
// else take info from col E
else val = getDesiredRangeValue("E", range, index);
// Take segment as needed
return getSegment(val,dataSegment);
}
}
)}
) : "false usage";
}
In order to make it work, I inserted an extra argument to the function. Now you will need to pass as an string the range in A1 notation in your ArrayFormula, this is because the input argument only gives you the values in the cells, and with that extra argument it will be possible to obtain extra info. To make it work fine, always use the same range as the next example shows:
=ArrayFormula(dataParse('RAW DATA'!D2:D5, 2,"D2:D5"))
or
=ArrayFormula(dataParse('RAW DATA'!D2:D, 2,"D2:D"))
Notice I also added a new function called getDesiredRangeValue, which will take the values from the column you need, depending if one of the cells from Col D has the value google. This is how the function looks:
/*
// A1 (String): The col from where you will want the info
// range (String): It will be used to get the info in a range
// index (Integer): It gives the index number from the main array gotten in the input arg
*/
function getDesiredRangeValue(A1, range, index){
var rowNumbers = range.match(/\d+/g);
// It checks if the range will has and end or it will prolong without specifying and end row
if(rowNumbers.length > 1){
var rangeCol = ss.getRange(A1 + rowNumbers[0] + ":" + A1 + rowNumbers[1]).getValues();
} else {
var rangeCol = ss.getRange(A1 + rowNumbers[0] + ":" + A1).getValues();
}
// It returns the whole value from each cell in the specified col
return rangeCol[index][0];
}
Code
Now your whole code will look like this:
// Global var
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("RAW DATA");
function getSegment(data,index){
temp=data.split("_");
return temp[index-1];
}
/*
// A1 (String): The col from where you will want the info
// range (String): It will be used to get the info in a range
// index (Integer): It gives the index number from the main array gotten in the input arg
*/
function getDesiredRangeValue(A1, range, index){
var rowNumbers = range.match(/\d+/g);
// It checks if the range will has and end or it will prolong without specifying and end row
if(rowNumbers.length > 1){
var rangeCol = ss.getRange(A1 + rowNumbers[0] + ":" + A1 + rowNumbers[1]).getValues();
} else {
var rangeCol = ss.getRange(A1 + rowNumbers[0] + ":" + A1).getValues();
}
// It returns the whole value from each cell in the specified col
return rangeCol[index][0];
}
// range (String): It will be used to get the info in a range
function dataParse(input,dataSegment, range){
var val = "";
return Array.isArray(input) ? input.map(function(e, index){
return e.map(function(f){
if(f!=""){
// If col D has value google then take info from col B
if(f === "google") val = getDesiredRangeValue("B", range, index);
// else take info from col E
else val = getDesiredRangeValue("E", range, index);
// Take segment as needed
return getSegment(val,dataSegment);
}
}
)}
) : "false usage";
}
Docs
These are the docs I used to help you:
Class Sheet
Custom Functions
I'm trying to write a Language Extension for VS Code in JavaScript and I seem to be missing something.
I have a Lexer.g4 and Parser.g4 for my language and can generate a tree using them.
My issue is that the VS Code API gives me a document and a position in that document (line #, character #). From any of the examples I've looked at for ANTLR4 I can't seem to find any functions generated that take a position in the file and give back the nodes of a tree at that position.
I want to know, for example that the cursor is placed on the name of a function.
Am I supposed to be walking the entire tree and checking the position of tokens to see if they enclose the position I'm in in the editor? Or maybe I'm not using the right tool for the job? I feel like I'm probably missing something more fundamental.
Yes, you have to walk the parse tree to find the context at a given position. This is a pretty simple task and you can see it in action in my ANLTR4 exension for vscode. There are multiple functions returning something useful for a given position. For instance this one:
/**
* Returns the parse tree which covers the given position or undefined if none could be found.
*/
function parseTreeFromPosition(root: ParseTree, column: number, row: number): ParseTree | undefined {
// Does the root node actually contain the position? If not we don't need to look further.
if (root instanceof TerminalNode) {
let terminal = (root as TerminalNode);
let token = terminal.symbol;
if (token.line != row)
return undefined;
let tokenStop = token.charPositionInLine + (token.stopIndex - token.startIndex + 1);
if (token.charPositionInLine <= column && tokenStop >= column) {
return terminal;
}
return undefined;
} else {
let context = (root as ParserRuleContext);
if (!context.start || !context.stop) { // Invalid tree?
return undefined;
}
if (context.start.line > row || (context.start.line == row && column < context.start.charPositionInLine)) {
return undefined;
}
let tokenStop = context.stop.charPositionInLine + (context.stop.stopIndex - context.stop.startIndex + 1);
if (context.stop.line < row || (context.stop.line == row && tokenStop < column)) {
return undefined;
}
if (context.children) {
for (let child of context.children) {
let result = parseTreeFromPosition(child, column, row);
if (result) {
return result;
}
}
}
return context;
}
}
I have a set of data. What i am looking forwards is to add 2 blank rows after each set of 3 values like this
Hope to get help in getting this solved.
you can find the sample google sheet here : https://docs.google.com/spreadsheets/d/11nMvUWn3xcTfxlk4v30KruPr03HSheMk1jrxZPpJ_p4/edit?usp=sharing
Thanks
Shijilal
Solution:
IF it's the third row, Add 3 bunnies separated by a space, else keep the values as it is
JOIN them all and SPLIT by a bunny and TRANSPOSE
Sample:
=ARRAYFORMULA(TRANSPOSE(SPLIT(TEXTJOIN("🐇",1,IF(MOD(ROW(A2:A16),3)=1,A2:A16&REPT("🐇 ",3),A2:A16)),"🐇")))
Some time ago, I created this custom function that may help you. I changed it slightly to meet your requirement and added it to the script editor.
function rowsBetween(range, s, rowsWithData, text) {
var n = [],
a = [],
i = 0;
while (i < s) {
a.push(text
)
i++;
}
range.forEach(function(r, i) {
n.push(r);
if((i + 2) % rowsWithData == 1) {
a.forEach(function(x) {
n.push(x);
});
}
});
return n;
}
This script will allow you to enter in the spreadsheet this (custom) formula (see also cell E2)
=rowsBetween(A2:A16, 2, 12,)
See if that works for you?
I have 30 columns and 1000 rows, I would like to compare column1 with another column. IF the value dont match then I would like to colour it red. Below is a small dataset in my spreadsheet:
A B C D E F ...
1 name sName email
2
3
.
n
Because I have a large dataset and I want to storing my columns in a array, the first row is heading. This is what I have done, however when testing I get empty result, can someone correct me what I am doing wrong?
var index = [];
var sheet = SpreadsheetApp.getActiveSheet();
function col(){
var data = sheet.getDataRange().getValues();
for (var i = 1; i <= data.length; i++) {
te = index[i] = data[1];
Logger.log(columnIndex[i])
if (data[3] != data[7]){
// column_id.setFontColor('red'); <--- I can set the background like this
}
}
}
From the code you can see I am scanning whole spreadsheet data[1] get the heading and in if loop (data[3] != data[7]) compare two columns. I do have to work on my colour variable but that can be done once I get the data that I need.
Try to check this tutorial if it can help you with your problem. This tutorial use a Google AppsScript to compare the two columns. If differences are found, the script should point these out. If no differences are found at all, the script should put out the text "[id]". Just customize this code for your own function.
Here is the code used to achieve this kind of comparison
function stringComparison(s1, s2) {
// lets test both variables are the same object type if not throw an error
if (Object.prototype.toString.call(s1) !== Object.prototype.toString.call(s2)){
throw("Both values need to be an array of cells or individual cells")
}
// if we are looking at two arrays of cells make sure the sizes match and only one column wide
if( Object.prototype.toString.call(s1) === '[object Array]' ) {
if (s1.length != s2.length || s1[0].length > 1 || s2[0].length > 1){
throw("Arrays of cells need to be same size and 1 column wide");
}
// since we are working with an array intialise the return
var out = [];
for (r in s1){ // loop over the rows and find differences using diff sub function
out.push([diff(s1[r][0], s2[r][0])]);
}
return out; // return response
} else { // we are working with two cells so return diff
return diff(s1, s2)
}
}
function diff (s1, s2){
var out = "[ ";
var notid = false;
// loop to match each character
for (var n = 0; n < s1.length; n++){
if (s1.charAt(n) == s2.charAt(n)){
out += "–";
} else {
out += s2.charAt(n);
notid = true;
}
out += " ";
}
out += " ]"
return (notid) ? out : "[ id. ]"; // if notid(entical) return output or [id.]
}
For more information, just check the tutorial link above and this SO question on how to compare two Spreadsheets.
I'm trying to create an iPhone app that takes the user's response to four criteria and, based on that, shows a specific set of data related to that permutation of answers. For example, in the main view controller:
User selects A or B in a segmented controller (let's say they choose A)
User selects C or D in a segmented controller (they choose D)
User selects E or F in a segmented controller (they choose E)
User inputs an age in a text box (they type in 37)
User touches the "Get Numbers" button
Based on the combination of "A, D, E, 37", the view that appears on the touch of "Get Numbers" shows an image overlaid with seven labels containing the numbers 17.1, 14.2, 30.0, 60.4, 18.1, 19.7 and 80.2. If the user had selected a different set of responses on the main controller, a different set of numbers would appear in those same labels.
I've researched the various elements, but I can't figure out how to combine them to produce the desired outcome. How can I do this? Any advice would be much appreciated--I'm quite new to xCode and completely stuck.
Thanks
I do not actually program in Xcode or Objective-C, but it seems to me that you are looking for a CASE statement. I found the following links, I hope they help:
the best way to implement readable switch case with strings in objective-c?
http://www.techotopia.com/index.php/The_Objective-C_switch_Statement
Based on your question, this is all contained in one viewController so you shouldn't need to pass a bunch of properties. The hard part is knowing how you are attempting to mutate the values and how much branching needs to happen. Also, you have 7 return values and there's no way of knowing how to compute these, like if the output from the first response is calculated with the second and third responses, etc.
EDIT, after reading your comment:
There are 8 possible outcomes, maybe you can create 8 methods to deal with each one. I can't think of any other way, but correct me if I'm wrong:
Possible values:
{
(A,C,E) ;
(B,C,E) ;
(A,D,E) ;
(B,D,E) ;
(A,C,F) ;
(B,C,F) ;
(A,D,F) ;
(B,D,F) ;
}
//Do it with an IF statement:
//first capture state into BOOL values
BOOL a = NO;
BOOL c = NO;
BOOL e = NO;
if (abSegment.selectedSegmentIndex == 0) { a = YES; }
if (cdSegment.selectedSegmentIndex == 0) { c = YES; }
if (efSegment.selectedSegmentIndex == 0) { e = YES; }
//next do some matching with IF statements
if (a && c && e) {
//do something for A,C,E
}
if (!a && c && e) {
//do something for B,C,E
}
if (a && !c && e) {
//do something for A,D,E
}
if (!a && !c && e) {
//do something for B,D,E
}
if (a && c && !e) {
//do something for A,C,F
}
if (!a && c && !e) {
//do something for B,C,F
}
if (a && !c && !e) {
//do something for A,D,F
}
if (!a && !c && !e) {
//do something for B,D,F
}
If you have hardcoded values you can just write the label updating text inside each IF block that matches your requirements. It's hacky but it's all I can think of right now