How can i get range number from A1notation? - google-apps-script

This is a script to get a1notation from a number.
Conversely, I don't know how to get the number from a1notation !
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(1, 1, 2, 5);
// Logs "A1:E2"
Logger.log(range.getA1Notation());
i want to get (1, 1, 2, 5) from "A1:E2"

Here is an example of how to get the row and column from A1 notation.
function test() {
try {
let spread = SpreadsheetApp.getActiveSpreadsheet();
let sheet = spread.getSheetByName("Sheet1");
let range = "A1:E2";
range = getRange(range);
console.log(range);
console.log( sheet.getRange(range[0][0],range[0][1],(range[1][0]-range[0][0]+1),(range[1][1]-range[0][1]+1)).getValues() );
range = "F3";
range = getRange(range);
console.log(range);
console.log( sheet.getRange(range[0][0],range[0][1]).getValue() );
}
catch(err) {
throw "Error in test: "+err;
}
}
function getRange(range) {
try {
let ranges = range.split(":");
ranges = ranges.map( text => {
let cell = text.toUpperCase();
let column = 0;
let row = 0;
let char = null;
for( let i=0; i<cell.length; i++ ) {
char = cell.charCodeAt(i);
if( ( char > 64 ) && ( char < 91 ) ) {
if( row > 0 ) return null;
column = (26*column)+char-64;
}
else if( ( char > 47 ) && ( char < 58 ) ) {
if( column === 0 ) return null;
row = (10*row)+char-48;
}
}
if( ( column === 0 ) || ( row === 0 ) ) throw "Incorrect range";
return [row,column];
}
);
return ranges;
}
catch(err) {
throw "\nError in getRange: "+err;
}
};
8:47:47 AM Notice Execution started
8:47:49 AM Info [ [ 1, 1 ], [ 2, 5 ] ]
8:47:49 AM Info [ [ 'Goodbye World', 'Date/Time', 'a', 'b', 'c' ],
[ 1,
Mon Nov 07 2022 06:34:37 GMT-0800 (Pacific Standard Time),
1,
101,
201 ] ]
8:47:49 AM Info [ [ 3, 6 ] ]
8:47:49 AM Info 302
8:47:48 AM Notice Execution completed

Related

Conditional combine of array objects Google apps script

I have a two dimensional array which elements needs to be combined if two of the elements of the sub arrays are equal.
Example:
I have this data:
Name
Date start
Date end
First
startDate1
endDate1
Second
startDate2
endDate2
Third
startDate1
endDate2
Fourth
startDate1
endDate1
Fifth
startDate1
endDate1
Sixth
startDate3
endDate2
I need this data:
Name
Date start
Date end
First, Fourth, Fifth
startDate1
endDate1
Second
startDate2
endDate2
Third
startDate1
endDate1
Sixth
startDate3
endDate2
The data is represented this way for example:
var event1 = [name, startDate1, endDate1];
var event2 = [name, startDate2, endDate2];
var event3 = [name, startDate1, endDate2];
var event4 = [name, startDate1, endDate1];
var event5 = [name, startDate1, endDate1];
var event6 = [name, startDate3, endDate2];
var allEvents = [event1, event2, event3, event4, event5, event6 ]
And I need to combine the elements with concatenated names if both start and end dates are equal.
Any help is much appreciated.
I'll leave it up to you where to put the results but try this:
function test() {
try {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Test");
var unique = [];
var data = sh.getRange(1,1,sh.getLastRow(),sh.getLastColumn()).getValues();
unique.push(data[1]);
var append = true;
for( var i=2; i<data.length; i++ ) {
append = true;
for( var j=0; j<unique.length; j++ ) {
if( ( data[i][1] === unique[j][1] ) && ( data[i][2] === unique[j][2] ) ) {
unique[j][0] = unique[j][0]+", "+data[i][0];
append = false;
break;
}
}
if( append ) unique.push(data[i]);
}
console.log(unique);
}
catch(err) {
console.log(err);
}
}
consol.log:
8:15:15 AM Info [ [ 'First, Fourth, Fifth', 'startDate1', 'endDate1' ],
[ 'Second', 'startDate2', 'endDate2' ],
[ 'Third', 'startDate1', 'endDate2' ],
[ 'Sixth', 'startDate3', 'endDate2' ] ]

Google Script to hide rows by 2 conditions, One word and one date

This is the first question I have posted on Stack Overflow so I apologize if I am doing this wrong. I have a tracker for work where I am trying to hide rows with a script that meets 2 conditions. 1. If a row contains "rejected" or "withdrew" 2. Date older than the previous quarter (in this case 1/1/2022). I can get the script to hide rows with just the words no problem but I have no clue how to do the date because I think it is a different syntax.
The dates are in column K, M, O, Q, S, U, W.
Here is the code I am currently using:
function Hide() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (var sheetI = 1; sheetI <= 3; sheetI++) {
var sheet = sheets[sheetI];
sheet.showRows(1, sheet.getMaxRows());
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Data Validation");
var v = s.getRange("A2").getValues();
var kk = SpreadsheetApp.getActiveSpreadsheet();
var k = kk.getSheetByName("SM");
var a = k.getRange("K:K").getValue();
var b = k.getRange("M:M").getValue();
var c = k.getRange("O:O").getValue();
var d = k.getRange("Q:Q").getValue();
var e = k.getRange("S:S").getValue();
var f = k.getRange("U:U").getValue();
var g = k.getRange("W:W").getValue();
var colJ = sheet.getRange("J:J").getValues().map(function(row) {return row[0];});
var colL = sheet.getRange("L:L").getValues().map(function(row) {return row[0];});
var colN = sheet.getRange("N:N").getValues().map(function(row) {return row[0];});
var colP = sheet.getRange("P:P").getValues().map(function(row) {return row[0];});
var colR = sheet.getRange("R:R").getValues().map(function(row) {return row[0];});
var colT = sheet.getRange("T:T").getValues().map(function(row) {return row[0];});
var colV = sheet.getRange("V:V").getValues().map(function(row) {return row[0];});
colJ.forEach(function(value, rowI) {
if (value === "rejected" && a < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && a < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colL.forEach(function(value, rowI) {
if (value === "rejected" && b < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && b < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colN.forEach(function(value, rowI)
{
if (value === "rejected" && c < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && c < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colP.forEach(function(value, rowI) {
if (value === "rejected" && d < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && d < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colR.forEach(function(value, rowI) {
if (value === "rejected" && e < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && e < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colT.forEach(function(value, rowI) {
if (value === "rejected" && f < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "withdrew" && f < v) {
sheet.hideRows(rowI + 1, 1);
}
});
colV.forEach(function(value, rowI) {
if (value === "accepted" && g < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "declined" && g < v) {
sheet.hideRows(rowI + 1, 1);
}
else if (value === "didn't extend" && g < v) {
sheet.hideRows(rowI + 1, 1);
}
});
}
}
Original look of sheet
Intended Look of sheet
Since nobody dares to dive deep into this problem (me included) for now, here is the partial solution.
This function returns true if a given date doesn't belong to current quarter:
function is_the_date_old_enough(checked_date) {
// which quarter the date belongs
const get_quarter_of = date => Math.ceil((date.getMonth()+1)/3);
// number of quarters in current date
var cur_date = new Date();
var cur_date_years = cur_date.getFullYear();
var cur_date_quarts = cur_date_years * 4 + get_quarter_of(cur_date);
// number of quarters in checked date
var checked_date_years = checked_date.getFullYear();
var checked_date_quarts = checked_date_years * 4 + get_quarter_of(checked_date);
// if the difference bigger than zero
return (cur_date_quarts - checked_date_quarts) > 0;
}
// tests (current date: 2022-01-14)
console.log(is_the_date_old_enough(new Date())); // false always
console.log(is_the_date_old_enough(new Date('2021-12-20'))); // true
console.log(is_the_date_old_enough(new Date('2021-09-05'))); // true
console.log(is_the_date_old_enough(new Date('2022-01-05'))); // false
console.log(is_the_date_old_enough(new Date('2000-01-05'))); // true
console.log(is_the_date_old_enough(new Date('2030-01-05'))); // false
Beware, the timezones can get you a headache for dates around first and last days of month. If you need to handle timezones it may require a more complicated solution. I suspect the variable cur_date should be defined with '00:00:00.00' time or something like that.

Google Sheets: split cells vertically and copy surrounding row entries

I need to do the following to optimize this sheet:
split each multi-line cell in column B so each email address will appear on a new row inserted under the original row.
Copy the data from cells in column A on the original row
I tried split+transpose formulas and a script I found here, but that is returning an error.
Here is the script:
function split_rows2(anArray) {
var res = anArray.reduce(function(ar, e) {
var splitted = e.slice(3, 12).map(function(f) {return f.toString().split(",").map(function(g) {return g.trim()})});
var temp = [];
for (var j = 0; j < splitted[0].length; j++) {
temp.push(e.slice(0, 3).concat(splitted.map(function(f) {return f[j] ? (isNaN(f[j]) ? f[j] : Number(f[j])) : ""})).concat(e.slice(12, 20)));
}
Array.prototype.push.apply(ar, temp);
return ar;
}, []);
return res;
}
=ArrayFormula(QUERY(SPLIT(FLATTEN({A2:A&"♦"&SPLIT(B2:B,",")}),"♦"),"select * where Col2 is not null",0))
Before:
Col1
Col2
A
1,2,3
B
4,5
After:
Col1
Col2
A
1
A
2
A
3
B
4
B
5
A multiline cell implies that they are delimited by line feeds '\n' not commas
function myfunk() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
let vs = sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).getValues();
sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).clearContent();
vs.forEach((r, i) => {
let t = r[1].toString().split('\n');
if (t.length > 1) {
t.forEach((e, j) => {
if(j == 0) {
r[1] = e;
} else {
let arr = Array.from(r, x => '');
arr[1] = e;
vs.splice(i + j, 0 , arr)
}
});
}
});
sh.getRange(2, 1, vs.length, vs[0].length).setValues(vs);
}
Sheet 0 after:
COL1
COL2
COL3
COL4
0
4
19
17
5
8
10
7
0
a
21
19
b
c
9
14
17
0

Depending on (Id). How to place this database (Ppt) in (MP04 / MP 05)

Description: I have a sheet (Ppto) with a list of IDs (Id), Credits(Cedent) and Debits(Recept). I would like to move these transactions to MP05, If Id are equal. If Ids are not equal move to MP04. Criterion: If Id = use MP05. If Id ≠ use MP04.
I'm a novice in google script, I need some support.
Thanks for your attention
function mp() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ppto = ss.getSheetByName('Ppto.');
var Id = ppto.getRange('B5:B12').getValues();
var cedent = ppto.getRange('D5:D12').getValues();
var recept = ppto.getRange('E5:E12').getValues();
for (var i = 0; i < cedent.length; i++) {
for (var j = 0; j < recept.length; j++) {
if (cedent[i] != '' ) {
if (recept[j] != '' ) {
//if (Id === Id) // MP-05
//if (Id != Id) // MP-04
{
ppto.getRange('H5:H12').setValues(cedent);
ppto.getRange('I5:I12').setValues(recept);
Logger.log(cedent[i]);
ppto.getRange('j5:j12').setValues(cedent);
ppto.getRange('k5:k12').setValues(recept);
}
}
}
}
}
}
Strategy:
FIFO: First-In First Out
Loop through all rows using forEach
If credit is present, Loop again through all rows using some to look for receipts
If credit e[2] in first loop equals receipts f[3] in second loop, Check for id [0]
If ID is equal, splice two empty columns at the end, else at the 2nd position to create a uniform 6-column array
Set that array back to the sheet.
Sample Script:
function transactionSegregator() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ppto = ss.getSheetByName('Ppto.');
var data = ppto.getRange('B5:E12').getValues();
data.forEach(function(e) {
//e: Each row
if (e[2] && e.length == 4) {
//e[2]:credits; If this row is not spliced
data.some(function(f) {
//f:Each row; Second loop
if (e[2] == f[3]) {
//if credits = debit
if (e[0] == f[0]) {
//if id = id, splice two empty columns after Col4, else after Col2
e.splice(4, 0, '', '');
f.splice(4, 0, '', '');
} else {
e.splice(2, 0, '', '');
f.splice(2, 0, '', '');
}
return true;
}
});
}
});
Logger.log(data);
ppto.getRange(5, 6, data.length, data[0].length).setValues(data);// F5
}
References:
Javascript tutorial
Array#forEach
Array#some
Array#splice

Online KML to Google Spreadsheet Script

Would like to use information into spreadsheets from a live Google Map (KML data). The code below handle it, but not as fast as required. It must handle up to 10 layers with about 2000 placemarks, line positions and/or polygon positions in the interesting (parameter "restrict") layer (or all layers). The size of the kml (xml) data is therefore often quite large.
Question 1: How (if possible) can caching and/or some other solution be implemented to handle about 2Mb xml data?
Question 2: How can what improvements be implemented to stream line the code, add flexibility to dynamically handle unknown (in advance) number of columns/rows and lower the execution time?
/**
* Fetch a Google Map and write the data to the spreadsheet (URL and layer).
*
* #param {url} input the URL associated with the Google Map (should contain &forcekml=1).
* #param {restrict} input the Layer name you want to restrict the data to.
* #return a range of data depending on the info in the map
* #customfunction
*/
function IMPORTMAP( url, restrict ) {
/* One key only allow 100k
var cache = CacheService.getPublicCache();
var cached = cache.get( "google-maps-xml" );
var cached = cache.getAll('?'); //Unknown keys in advance that also may change from time to time.
if ( cached != null ) {
return cached;
}*/
var txt = UrlFetchApp.fetch( url ).getContentText();
var sheet = SpreadsheetApp.getActiveSheet();
var width = sheet.getMaxColumns();
var height = sheet.getMaxRows();
var xmlDoc = XmlService.parse( txt );
var root = xmlDoc.getRootElement();
var atom = XmlService.getNamespace( 'http://www.opengis.net/kml/2.2' );
var xml2csv = [[height],[10]];
var labels = [], label = '', counter = 0, o = 0;
var documents = root.getChildren( 'Document', atom );
for( var i = 0; i < documents.length; i++ ) {
var Folders = documents[i].getChildren( 'Folder', atom );
for( var j = 0; j < Folders.length && j <= height; j++ ) {
if( Folders[j].getChild( 'name', atom ).getValue() == restrict ) {
var Placemarks = Folders[j].getChildren( 'Placemark', atom );
for( var k = 0; k < Placemarks.length; k++ ) {
var nodes = Placemarks[k].getChildren();
for( var l = 0; l < nodes.length; l++ ) {
var data = nodes[l].getChildren();
if( data.length > 0 ) {
for( var m = 0; m < data.length && counter <= width; m++ ) {
if( data[m].getAttribute( 'name' ) != null ) {
if( labels[ data[m].getAttribute( 'name' ).getValue().trim() ] == null ) {
labels[ data[m].getAttribute( 'name' ).getValue().trim() ] = counter;
xml2csv[ 0 ][ counter++ ] = data[m].getAttribute( 'name' ).getValue().trim();
}
}
if( data[m].getChild( 'value', atom ) != null ) {
xml2csv[ k + 1 ][ labels[ data[m].getAttribute( 'name' ).getValue().trim() ] ] = data[m].getChild( 'value', atom ).getValue().trim();
} else {
o = labels[ data[m].getName().trim() ];
if( o == null ) {
labels[ data[m].getName().trim() ] = counter;
o = counter;
xml2csv[ 0 ][ counter++ ] = data[m].getName().trim();
}
if( xml2csv[ k + 1 ] == null ) {
xml2csv[ k + 1 ] = new Array( counter );
}
xml2csv[ k + 1 ][ labels[ data[m].getName().trim() ] ] = data[m].getValue().trim();
}
}
} else {
if( label == '' )
label = nodes[l].getName().trim();
o = labels[ nodes[l].getName().trim() ];
if( o == null ) {
labels[ nodes[l].getName().trim() ] = counter;
o = counter;
xml2csv[ 0 ][ counter++ ] = nodes[l].getName().trim();
}
if( xml2csv[ k + 1 ] == null ) {
xml2csv[ k + 1 ] = new Array( counter );
}
xml2csv[ k + 1 ][ o ] = nodes[l].getValue().trim();
}
}
}
}
}
}
//cache.putAll( xml2csv, 1500 ); // cache for 25 minutes
return xml2csv;
}
Please note that code only handle specific kml data in its current form and may not be suitable for a wider audience.