ArrayFormula For Join A Range Column - if-statement

I want to use ArrayFormula for JoinText for multiple columns, From Column A to Column H. I already have Google App Script for it, and it works.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DISPOSISI");
const rowNo = sheet.getLastRow();
const colStaff1 = 1;
const colStaff8 = 8;
const colJoinStaff = 9;
// =============
// TEXT JOIN :
// =============
const cellStaff1 = sheet.getRange(rowNo,colStaff1).getA1Notation();
const cellStaff8 = sheet.getRange(rowNo,colStaff8).getA1Notation();
sheet.getRange(rowNo,colJoinStaff).setValue(sheet.getRange(rowNo,colJoinStaff).setFormula('TEXTJOIN(", ";TRUE;'+cellStaff1+':'+cellStaff8+')').getValue());`
Every I added one new Row, I want the result will appear with ArrayFormula.
This is my formula :
=arrayformula(if(row(A:A)=1;"JOIN VALUE WITH COMMA";ARRAYFORMULA(IF((A:A)="";"";ARRAYFORMULA(TEXTJOIN(", ";TRUE;(A:A):(H:H)))))))
But it does not work.
My Spreadsheet

try:
={"JOIN VALUE WITH COMMA";
INDEX(REGEXREPLACE(TRIM(FLATTEN(QUERY(TRANSPOSE(
IF(A2:H="";;A2:H&","));;9^9))); ",$"; ))}
or maybe:
={"JOIN VALUE WITH COMMA";
INDEX(REGEXREPLACE(TRIM(FLATTEN(QUERY(TRANSPOSE(
IF(A2:H="";;A1:H1&": "&A2:H&","));;9^9))); ",$"; ))}

Related

Google script - In the following code, instead of 'includes', how to do 'not includes'

Sample sheet
This is the code I have now, and what I want to do is also bring in all data from C where text does not include '250p' in col A.
const sS = SpreadsheetApp.getActiveSpreadsheet()
function grabData() {
const sheetIn = sS.getSheetByName('data')
const sheetOut = sS.getSheetByName('Desired Outcome')
const range = 'A2:B'
/* Grab all the data from columns A and B and filter it */
const values = sheetIn.getRange(range).getValues().filter(n => n[0])
/* Retrieve only the names if it containes 250p */
/* In format [[a], [b], ...] */
const parsedValues = values.map((arr) => {
const [type, name] = arr
if (type.toLowerCase().includes('250p')) {
return name.split('\n')
}
})
.filter(n => n)
.flat()
.map(n => [n])
/* Add the values to the Desired Outcome Sheet */
sheetOut
.getRange(sheetOut.getLastRow() + 1, 1, parsedValues.length)
.setValues(parsedValues)
}
I tried doing:
if (!type.toLowerCase().includes('250p')) {
if (type.whenTextDoesNotContain('250p')) {
But on both occasions I get that, that is not a function.
I believe your goal is as follows.
Your Spreadsheet has the values in the columns "A" and "C".
You want to check the column "A". When the value of column "A" doesn't include the text of 250p, you want to copy the values from the column "C" to the column "A" of the destination sheet. In this case, you want to split the values by \n.
Modification points:
In your script, in order to retrieve the values from the columns "A" and "C", I thought that const range = 'A2:B' should be const range = 'A2:C' + sheetIn.getLastRow();, and also const [type, name] = arr is const [type, , name] = arr.
In order to retrieve the rows that 250p is not included in the column "A", I modified your if statement to if (!type.toLowerCase().includes('250p')) {.
When these points are reflected to your script, it becomes as follows.
Modified script:
const sS = SpreadsheetApp.getActiveSpreadsheet();
function grabData() {
const sheetIn = sS.getSheetByName('data');
const sheetOut = sS.getSheetByName('Desired Outcome');
const range = 'A2:C' + sheetIn.getLastRow();
const values = sheetIn.getRange(range).getValues();
const parsedValues = values.map((arr) => {
const [type, , name] = arr;
if (!type.toLowerCase().includes('250p')) {
return name.split('\n');
}
})
.filter(n => n)
.flat()
.map(n => [n]);
sheetOut
.getRange(sheetOut.getLastRow() + 1, 1, parsedValues.length)
.setValues(parsedValues);
}
If you want to retrieve the rows that 250p is included in the column "A", please modify if (!type.toLowerCase().includes('250p')) { to if (type.toLowerCase().includes('250p')) {.
Note:
In this modified script, your provided Spreadsheet is used. So, when you change the Spreadsheet, this modified script might not be able to be used. Please be careful about this.

Get last row ignoring formula in google script

I used a google script that move row from one sheet to another from column A to column D. On column E i have a formula. How can i put data on last row from Column A to D from example, ignoring formula from column E. Can someone help me with this?
function onEdit(e){
let r = e.range;
if (r.columnStart != 4 || r.rowStart == 1 || e.value == null) return;
const sh = SpreadsheetApp.getActive();
const valArray = ["Waiting","In progress","Complete"];
const destArray = ["Order","Open order","Complete order"];
let dest = sh.getSheetByName(destArray[valArray.indexOf(e.value)]);
let src = sh.getActiveSheet();
if (dest.getName() == src.getName()) return;
src.getRange(r.rowStart,1,1,4).moveTo(dest.getRange(dest.getLastRow()+1,1,1,4));
src.deleteRow(r.rowStart);
}
Here an example of my problem, maybe this will explain better:https://docs.google.com/spreadsheets/d/1qowADCPYiyej25ezXtjVLO5fvg9Gr9rolX3bh2-ZAG4/edit#gid=0
Replace dest.getLastRow() by dest.getLastDataRow('A') and add this function:
Object.prototype.getLastDataRow = function(col){
var lastRow = this.getLastRow();
var range = this.getRange(col + lastRow);
if (range.getValue() !== "") {
return lastRow;
} else {
return range.getNextDataCell(SpreadsheetApp.Direction.UP).getRow();
}
};
I still sugest you to erase all formulas in column E and put in E1
={"price * 2";ARRAYFORMULA(if(C2:C>0;C2:C*2;""))}
so that the formula will populate / will be active the new row

Google Sheets Apps Script - How to add an Arrayformula and multiple associated IF functions within a script (Without showing the formula within UI)

I was wondering if someone is able to assist?
I'm trying to add an Arrayformula consisting of two IF functions, so I'm wanting to merge the following two formulas into one cell:
=ARRAYFORMULA(IF(D13:D104="","",(IF(K13:K104,K13:K104*20,"$0"))))
=ARRAYFORMULA(IF(D105:D="","",(IF(K105:K,K105:K*C4,"$0"))))
So the first section of the sheet needs to be multiplied by 20, and then the figure has changed and needs to be multiplied by 25 (which is cell C4)
Is it possible to merge these into one cell containing an Arrayformula+the two IF functions (or is there another/easier way for this)
Is it possible to add this into Google Apps Script so that it works in the backend (so not just a script that applies the formula into a cell - but doesn't show in the frontend or sheet)
More of a general question - When using Arrayformula with IF; and for example the output is specific text e.g. "Test Complete" associated to the range F2:F (checking if E2:E contains a particular phrase e.g. "Done") - for the empty cells in between (due to setting the False outcome as "") is it possible to somehow randomly add data into these blank cells without interrupting the formula? (so I have to option for automated text if the cell to the left states a particular term/word, but still have the option to manually add random data into blank cells)
Any assistance would be greatly appreciated
As for 1st and 2nd questions: it looks like a task for a custom function. Something like this:
function MULTI() {
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getActiveCell();
var row = cell.getRow();
var value = sheet.getRange('K'+row).getValue();
return (row < 105) ? value * 20 : value * 25;
}
It gets a value from column K and multiplies it by 20 if the row less than 105 and by 25 for the rest of rows.
Here is the variant of the same formula that uses the cell 'C4':
function MULTIC4() {
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getActiveCell();
var row = cell.getRow();
var value = sheet.getRange('K'+row).getValue();
var c4 = sheet.getRange('C4').getValue();
return (row < 105) ? value * 20 : value * c4;
}
And it can be done with the trigger onEdit():
function onEdit(e) {
var col = e.range.columnStart;
if (col != 11) return; // 11 = K
var sheet = e.source.getActiveSheet();
if (sheet.getName() != 'Sheet1') return;
var c4 = sheet.getRange('C4').getValue();
var row = e.range.rowStart;
var dest_cell = sheet.getRange('D'+row);
var value = sheet.getRange(row,col).getValue();
var result = (row < 105) ? value * 20 : value * c4;
dest_cell.setValue(result);
}
It recalculates automatically the value in the cell of column 'D' (current row) every time when you're changing value in the cell of column 'K'. On the sheet 'Sheet1'.

google sheets Get the last non-empty cell in a ROW

this is the simplified version of my data.
How can I calculate E and F columns? the address format of E column is not important.
put this custom formula to E2 =last_item_index(A2:D)
and here is the custom function code:
/**
* #customfunction
*/
function last_item_index(range) {
const colCount = range[0].length
const lastItemIndices = range.map(row=>{
const indexFirstNonEmpty = row.reverse().findIndex(cell=>cell)
const indexLastNonEmpty = colCount - 1 - indexFirstNonEmpty
return indexFirstNonEmpty>=0? [indexLastNonEmpty, row[indexFirstNonEmpty]] : ['','']
})
return lastItemIndices
}
The value returned in column E will be the zero-based index of the last non-empty item. You can easy convert it to A1-formatted range with ADDRESS function.
try:
=INDEX(IFNA(REGEXEXTRACT(" "&TRIM(FLATTEN(QUERY(TRANSPOSE(IF(A2:D="",,
ADDRESS(ROW(A2:A), COLUMN(A:D), 4))),,9^9))), " (.{1,3}\d+)$")))
and:
=INDEX(IFNA(SUBSTITUTE(REGEXEXTRACT(" "&TRIM(FLATTEN(QUERY(TRANSPOSE(IF(A2:D="",,
SUBSTITUTE(A2:D, " ", "♦"))),,9^9))), "((?:[^ ]+ *){1})$"), "♦", " ")))

Extract the digits and append it in a different cell?

I am trying to automatically RegExp(extract) the digits(AREA number) in Column 3 combined with the Text 'A' to append in Column 1 Date INDEX.
The problem is I'm not yet familiar in using google sheets app-scripts.
Tried looking for solutions with similar situation as me, but to no avail.
I don't know to put VBA to app-scripts.
Tried using some codes.
I still can't seem to make it work.
Can anyone point me in the right direction?
Thank you if you can help me out. Thanks.
EDIT:
The scenarios is in the office i cant make column for the formula.
It must be "behind the scene".
My googlesheets
//NOT WORKING code
function onEdit(e) {
var rg=e.range;
var sh=e.range.getSheet();
var area=sh.getName();
var regExp = new RegExp("\d*"); // Extract the digits
var dataIndex = regExp.exec(area)[1];
if(rg.columnStart==3) { // Observe column 3
var vA=rg.getValues();
for(var i=0;i<vA.length;i++){
if(vA[i][0]) {
sh.getRange(rg.rowStart + i,1).appendText((dataIndex) +'A'); // append to column 1 with 'A' and extracted digits
}
}
}
}
This answer extends your approach of using a script with an OnEdit trigger. But there are a number of differences between the two sets of code.
The most significant difference is that I have used the Javascript split method (var fields = value.split(' ');) to get distinct values from the data entry.
Most of the other differences are error checking:
if(rg.columnStart === 3 && area === "work") {: test for sheet="work" as well as an edit on Column C
var value = e.value.toUpperCase();: anticipate that the test might be in lower case.
if (fields.length !=2){: test that there are two elements in the data entry.
if (fields[0] != "AREA"){: test that the first elment of the entry is the word 'area'
if (num !=0 && numtype ==="number"){; test that the second element is a number, and that it is NOT zero.
if (colA.length !=0){: test that Column A is not empty
var newColA = colA+"A"+num;: construct the new value for Column A by using unary operator '+'.
function onEdit(e){
// so5911459101
// test for edit in column C and sheet = work
var ss = SpreadsheetApp.getActiveSpreadsheet;
// get Event Objects
var rg=e.range;
var sh=e.range.getSheet();
var area=sh.getName();
var row = rg.getRow();
// test if the edit is in Column C of sheet = work
if(rg.columnStart === 3 && area === "work") { // Observe column 3 and sheet = work
//Logger.log("DEBUG: the edit is in Column C of 'Work'")
// get the edited value
var value = e.value.toUpperCase();
//Logger.log("DEBUG: the value = "+value+", length = "+value.length+", uppercase = "+value.toUpperCase());
// use Javascript split on the value
var fields = value.split(' ');
//Logger.log(fields);//DEBUG
// Logger.log("DEBUG: number of fields = "+fields.length)
// test if there are two fields in the value
if (fields.length !=2){
// Logger.log("DEBUG: the value doesn't have two fields")
}
else{
// Logger.log("DEBUG: the value has two fields")
// test if the first field = 'AREA'
if (fields[0] != "AREA"){
// Logger.log("DEBUG: do nothing because the value doesn't include area")
}
else{
// Logger.log("DEBUG: do something because the value does include area")
// get the second field - it should be a value
var num = fields[1];
num =+num
var numtype = typeof num;
// Logger.log("DEBUG: num= "+num+" type = "+numtype); //number
// test type of second field
if (num !=0 && numtype ==="number"){
// Logger.log("DEBUG: the second field IS a number")
// get the range for the cell in Column A
var colARange = sh.getRange(row,1);
// Logger.log("DEBUG: the ColA range = "+colARange.getA1Notation());
// get the value of Column A
var colA = colARange.getValue();
// Logger.log("DEBUG: Col A = "+colA+", length = "+colA.length);
// test if Column A is empty
if (colA.length !=0){
var newColA = colA+"A"+num;
// Logger.log("DEBUG: the new cola = "+newColA);
// update the value in Column A
colARange.setValue(newColA);
}
else{
// Logger.log("DEBUG: do nothing because column A is empty")
}
}
else{
// Logger.log("DEBUG: the second field isn't a number")
}
}
}
}
else{
//Logger.log("DEBUG: the edit is NOT in Column C of 'Work'")
}
}
REVISION
If the value in Column C is sourced from data validation, then no need for and testing except that the edit was in Column C and the sheet = "work".
Included two additional lines of code:
var colAfields = colA.split('-');
var colAdate = colAfields[0];
This has the effect of excluding any existing characters after the hyphen, and re-establishing the hyphen, row number plus "A" and the AREA numeral.
function onEdit(e){
// so5911459101 revised
// only one test - check for ColumnC and sheet="work"
// test for edit in column C and sheet = work
var ss = SpreadsheetApp.getActiveSpreadsheet;
// get Event Objects
var rg=e.range;
var sh=e.range.getSheet();
var area=sh.getName();
var row = rg.getRow();
// test if the edit is in Column C of sheet = work
if(rg.columnStart === 3 && area === "work") { // Observe column 3 and sheet = work
Logger.log("DEBUG: the edit is in Column C of 'Work'")
// get the edited value
var value = e.value
//Logger.log("DEBUG: the value = "+value+", length = "+value.length);
// use Javascript split on the value
var fields = value.split(' ');
//Logger.log(fields);//DEBUG
// get the second field - it should be a value
var num = fields[1];
// get the range for the cell in Column A
var colARange = sh.getRange(row,1);
// Logger.log("DEBUG: the ColA range = "+colARange.getA1Notation());
// get the value of Column A
var colA = colARange.getValue();
// Logger.log("DEBUG: Col A = "+colA+", length = "+colA.length);
// use Javascript split on Column A in case of existing value
var colAfields = colA.split('-');
var colAdate = colAfields[0];
// build new value
var newColA = colAdate+"-"+row+"A"+num;
// Logger.log("DEBUG: the new cola = "+newColA);
// update the value in Column A
colARange.setValue(newColA);
}
else{
Logger.log("DEBUG: the edit is NOT in Column C of 'Work'")
}
}