Good day everyone!
I'd like to have a function similiar to VBA's intersect
in Google Sheets Script. Is there a nifty way to do this? The function must return:
RangeIntersect(R1, R2) = true
if R1 has common cells with R2,RangeIntersect(R1, R2) = false
if R1 has no common cell with R2Thank you in advance.
Speed test
I want the function to work as fast as possible. That's because it would be used in loops inside onEdit
function. If you like, test provided function with this script:
function speedtest () {
var sheet;
sheet = SpreadsheetApp.getActiveSheet();
var rr1 = ['A1:C16', 'B2:B88', 'D1:D8', 'E1:E17', 'A18:B51', 'A13:A14', 'A17:C17'];
var r1, r2;
r1 = sheet.getRange(rr1[0]);
var rr2 = [];
// define some ranges
for (var x = 0; x < 30; x++) {
for (var i = 0; i < rr1.length; i++) {
r2 = sheet.getRange(rr1[i]);
rr2.push(r2);
}
}
var C;
var start, end, time;
// timer start
for (var t = 0; t < 10; t++) {
start = new Date().getTime();
for (var f = 0; f < rr2.length; f++) {
C = RangeIntersect(r1, rr2[f]);
}
end = new Date().getTime();
time = end - start;
Logger.log('Execution time = ' + time);
}
}
Equality (==): a == b results in true if the value a is equal to value b. Strict equality (===): a === b results in true if the value a is equal to value b and their types are also the same. Inequality (! =): a !=
Use getRangeByName() to reference a named range by using its name. Use getRange() to reference a range using its A1 notation or row and column indices.
To use the LEN function, simply enter the text string that you want to calculate the number of characters for, and then press the Enter key. The LEN function will return the number of characters in the text string.
First, you will need to get your range coordinates:
function Coordinates (range) {
var self = this
;
self.x1 = range.getColumn();
self.y1 = range.getRow();
self.x2 = range.getLastColumn();
self.y2 = range.getLastRow();
}
Second, you will need to know if the column bounds and row bounds overlap:
function Overlaps (a, b, c, d) {
return (a >= c && a <= d) || (b >= c && b <= d) || (c >= a && c <= b) || (d >= a && d <= b);
}
Your requested function to compare two ranges:
function RangeIntersect (R1, R2) {
R1 = new Coordinates (R1);
R2 = new Coordinates (R2);
return (Overlaps(R1.x1, R1.x2, R2.x1, R2.x2) && Overlaps(R1.y1, R1.y2, R2.y1, R2.y2));
}
And here's a quick test:
function test () {
var sheet, r1, r2, r3
;
sheet = SpreadsheetApp.getActiveSheet();
r1 = sheet.getRange(1, 1, 2, 2);
r2 = sheet.getRange(2, 2, 2, 2);
r3 = sheet.getRange(4, 4);
Logger.log("%s %s overlap %s", r1.getA1Notation(), (RangeIntersect(r1, r2) ? "does" : "does not"), r2.getA1Notation());
Logger.log("%s %s overlap %s", r2.getA1Notation(), (RangeIntersect(r2, r3) ? "does" : "does not"), r3.getA1Notation());
Logger.log("%s %s overlap %s", r1.getA1Notation(), (RangeIntersect(r1, r3) ? "does" : "does not"), r3.getA1Notation());
return;
}
Please note that this is just a quick solution. Also note that getActiveRange will include any rows and columns hidden through hide or filtering and would otherwise be included in the selected range.
Added 2016-05-04
A shortened version of Max's quicker solution with a single return (I prefer a single exit point):
function RangeIntersect (R1, R2) {
return (R1.getLastRow() >= R2.getRow()) && (R2.getLastRow() >= R1.getRow()) && (R1.getLastColumn() >= R2.getColumn()) && (R2.getLastColumn() >= R1.getColumn());
}
I've made my own version of this script:
function RangeIntersect(R1, R2) {
var LR1 = R1.getLastRow();
var Ro2 = R2.getRow();
if (LR1 < Ro2) return false;
var LR2 = R2.getLastRow();
var Ro1 = R1.getRow();
if (LR2 < Ro1) return false;
var LC1 = R1.getLastColumn();
var C2 = R2.getColumn();
if (LC1 < C2) return false;
var LC2 = R2.getLastColumn();
var C1 = R1.getColumn();
if (LC2 < C1) return false;
return true;
}
This script works ~1.4 times faster because it returns each time when 2 ranges don't intersect.
Update Tested with v8 engine. Speed of all suggested solutions are almost the same:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With