1
votes

ISSUE

I have a spreadsheet whereby I generate the end column based on the other columns present. I do this using the app script code below. There are now 1147 rows in this spreadsheet and I often notice a long period of loading to retrieve all of the rows.

Are there any suggestions on how I can improve the efficiency and responsiveness?

EXAMPLE

enter image description here

ARRAY FORMULA ON END COLUMN

=ARRAYFORMULA(
IF(A2:A="Spec", "# SPEC "&B2:B, 
IF(A2:A="Scenario", "## "&B2:B, 
IF(A2:A="Step", "* "&TAGS(C2:C,D2:D), 
IF(A2:A="Tag", "Tags: "&REGEXREPLACE(B2:B,"\s",""), 
IF(A2A="", ""))))))

APP SCRIPT CODE

Utilities.sleep(3000)
/** @OnlyCurrentDoc */

function TAGS(input,textreplacement) {
  if (input.length > 0) {
    var lst = input.split(",")
    var rep = textreplacement.match(/<[^>]*>/g)
    for (i in rep){
      textreplacement = textreplacement.replace(rep[i],'"'+lst[i]+'"')
    }
    return textreplacement
  }
  else{
    return textreplacement
  }
}

EDIT

From the image below I would like to replace everything with triangle brackets < > in column D, with the values in column C, separated by comma.

I use the Array Formula in column E to do an initial conversion and then use the TAGS function to add in the values.

Ideally I would use the Array Formula in one cell at the top of column E to do all the replacements.

enter image description here

2
Why do you have delay outside of the functions?Cooper

2 Answers

1
votes

Custom functions in Google Apps Script tend to take long time to process and I wouldn't recommend to use it in several cells. I would like to understand better what you trying to do with this data in order to answer properly, but anyway, I would try one of these two solutions:

1 - Inline formula:

Using only native functions has a better performance. Not sure how you could achieve this, since you are iterating inside that TAGS function.

2- Calculate values interely with Script and replace values in column E:

You could create a function that may run from onEdit event or get activated by a custom menu. Generally it would be like this:

function calculateColumnE() {
  var sheet = SpreadsheetApp.openById('some-id').getSheetByName('some-name');
  var row_count = sheet.getLastRow();
  var input_data = sheet.getRange(1, 1, row_count, 4).getValues();
  var data = [];
  for (var i = 0; i < row_count; i++) {
      var row_data; // this variable will receive value for column E in this row
      /*
      ...
      manage input_data here
      ...
      */
      data.push([row_data]); // data array MUST be a 2 dimensional array
  }

  sheet.getRange(1, 5, data.length, 1).setValues(data);
}

EDIT

Here is the full code for solution 2:

function TAGS(input,textreplacement) { //keeping your original function
  if (input.length > 0) {
    var lst = input.split(",")
    var rep = textreplacement.match(/<[^>]*>/g)
    for (i in rep){
      textreplacement = textreplacement.replace(rep[i],'"'+lst[i]+'"')
    }
    return textreplacement
  }
  else{
    return textreplacement
  }
}

function calculateColumnE() {
  var sheet = SpreadsheetApp.openById('some-id').getSheetByName('some-name');
  var row_count = sheet.getLastRow();
  var input_data = sheet.getRange(1, 1, row_count, 4).getValues();
  var data = [];
  for (var i = 0; i < row_count; i++) {
      var row_data; // this variable will receive value for column E in this row
      if (input_data[i][0] == "Spec") {
        row_data = "# SPEC " + input_data[i][1];
      } else if (input_data[i][0] == "Scenario") {
        row_data = "## " + input_data[i][1];
      } else if (input_data[i][0] == "Step") {
        row_data = "* " + TAGS(input_data[i][2], input_data[i][3]);
      } else if (input_data[i][0] == "Tag") {
        row_data = "Tags: " + input_data[i][1].replace(/\s/, ''); // not sure what this is doing
      } else if (input_data[i][0] == "") {
        row_data = "";
      }
      data.push([row_data]); // data array MUST be a 2 dimensional array
  }
  sheet.getRange(1, 5, data.length, 1).setValues(data);
}

I also created a working example, which you can check here: https://docs.google.com/spreadsheets/d/1q2SYD7nYubSuvkMOKQAFuGsrGzrMElzZNIFb8PjM7Yk/edit#gid=0 (send me request if you need it). It works like a charm using onEdit event to trigger calculateColumnE() with few lines, I'm curious to know about the result in your 1000+ rows sheet. If it get slow, you may need to run this function manually.

0
votes

Not sure if this will be faster:

function TAGS(input,tr) {
  if (input.length > 0) {
    var lst = input.split(",");
    var i=0;
    tr=tr.replace(/<[^>]*>/g,function(){return '"' + lst[i++] + '"';});
  }
  return tr;
}