1
\$\begingroup\$

I'm not a scripting expert by any means, but I put together some code that I needed for Google Sheets. The good news is that it actually works!

However, it's noticeably slow to run (about 15 seconds). I'm sure it's not optimized to deal with arrays and other fun things that I don't fully understand...

function ShowHideClosedCards() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();
  var lastRow = sheet.getLastRow();

  strVisible = sheet.getRange('N1').getValue(); //Get the value of N1
  if (strVisible == '** Closed accounts are visible **') { //If the closed accounts are visible...
      for( i=6 ; i<=lastRow ; i++) { // Start with row 6 and continue through the last row: i <= lastRow
       var status = sheet.getRange("F"+i).getValue(); //Get the value of the cell.
       if (status !== "") { // If there's something in the "Date Closed" cell, then that should mean it's closed
         sheet.hideRows(i); // Hide the row
       } 
       }
       sheet.getRange('N1').setValue('** Closed accounts are hidden **');
  } else {  // Otherwise, assume the closed accounts are hidden...
       for( i=6 ; i<=lastRow ; i++) { // Start with row 6 and continue through the last row: i <= lastRow
       var status = sheet.getRange("F"+i).getValue(); //Get the value of the cell.
       if (status !== "") { // If there's something in the "Date Closed" cell, then that should mean it's closed
         sheet.showRows(i); // Show the row
       } 
       }
       sheet.getRange('N1').setValue('** Closed accounts are visible **');
  } 
}

The gist of it is that it should go through each row (from 6 through 500) and if there's anything in column F of that row, hide the row. Then it marks one cell (N1) to let the user know that the closed accounts are hidden.

If the user runs the code again, it should do the same thing, but unhide those rows (and only those rows). Then it marks N1 again to let the user know that the closed accounts are visible.

Any suggestions on how to get it to run faster?

\$\endgroup\$
7
  • 1
    \$\begingroup\$ There is an entire page in the docs about how to improve performance and what DOs and DON'Ts there are. In your case you should not be accessing each cell one by one withsheet.getRange("F"+i) but instead read an entire range in to an array and work with this. It's very fast that way. \$\endgroup\$
    – t3chb0t
    Commented Jul 25, 2018 at 19:39
  • \$\begingroup\$ That's a fair statement, but I was hoping for a little more help. Like I mentioned, I'm not really an expert in this area and don't quite comprehend arrays. Can you give me a little more on the direction of how to do this? \$\endgroup\$
    – Jim
    Commented Jul 25, 2018 at 19:56
  • \$\begingroup\$ I'll get back to you tomorrow... unless someone else is faster than me :-] \$\endgroup\$
    – t3chb0t
    Commented Jul 25, 2018 at 20:07
  • \$\begingroup\$ Hi @t3chb0t - just wanted to see if you had a chance to look at this yet? \$\endgroup\$
    – Jim
    Commented Jul 27, 2018 at 13:00
  • \$\begingroup\$ Sorry, I was too busy but I didn't forget you ;-] \$\endgroup\$
    – t3chb0t
    Commented Jul 27, 2018 at 13:01

1 Answer 1

3
\$\begingroup\$

In order to improve the performance of your script you should read cell values from an array that represents the entire range that your are going to scan.

This means that instead of repetedly calling

var status = sheet.getRange("F"+i).getValue(); //Get the value of the cell.

you should get everything in a single call like this one

var values = getRange(row, column, numRows, numColumns).getValues();

it'll give you an array that you can iterate very fast. Example:

for (var row in values) {
  for (var col in values[row]) {
      ...
  }
}

Hiding rows can be a little bit tricky if you want to optimize it becasue it requries some additional work. If you do it for each row separately then you'll loose some performance agian. This means that this is not good:

sheet.hideRows(i); // Hide the row

In my scripts that work with a few hundereds or thousands rows hiding some of them lasts no longer than 1-2 seconds.

Here's how it goes:

I have a special column that I call Visible (or whatever). I use it to store a boolean value.

When I run a loop I store the flag in a second array like var visibles = []; instead of calling hideRows each time.

After the loop is finished I update the Visible column with:

// update row visibility
var visibleRange = sheet.getRange(row, column, numRows, numColumns);
visibleRange.setValues(visibles);

This runs super fast.

Next you have to unhide all rows with:

// show all rows
sheet.showRows(rowIndex, numRows);

You have to sort them by visibility:

// sort by 'visible' and make 'true' (visible) rows first
sheet.sort(..., false);  

Sorting is necessary so that you can finally hide an entire range in a blink of an eye:

// hide 'false' (not-visible) rows
var rangeToHide = sheet.getRange(.., .., ..);
SpreadsheetApp.getActiveSpreadsheet().hideRow(rangeToHide);

If you need a different order you can sort it again after hiding.

With this solution it requires just a couple of calls which will make your script really smooth.


You can read about a couople more optimization tipps on Google Apps Script - Best Practices

\$\endgroup\$
5
  • \$\begingroup\$ I'll see if I can piece it together and make it work and I'll let you know. Thanks so much for your help! \$\endgroup\$
    – Jim
    Commented Aug 1, 2018 at 18:38
  • \$\begingroup\$ Well, I was able to get the array working for the first part of the script, but the hiding/unhiding is a problem. The user will have the rows in a particular order to their liking, but not sorted in any way. So if I sort/unsort and then hide/unhide the rows, I won't be able to put it back the way it was. Any ideas on how to overcome that? \$\endgroup\$
    – Jim
    Commented Aug 3, 2018 at 12:08
  • \$\begingroup\$ @Jim I would create another helper column for sorting. When you loop over the data you can just put numbers in the other column and use it for sorting after hiding rows. \$\endgroup\$
    – t3chb0t
    Commented Aug 3, 2018 at 13:32
  • \$\begingroup\$ Nice! I'll give it a shot! \$\endgroup\$
    – Jim
    Commented Aug 3, 2018 at 15:34
  • \$\begingroup\$ It looks like I'm not going to get to finish this for a while. But, your code samples definitely got me rolling in the right direction. Thanks for your help! \$\endgroup\$
    – Jim
    Commented Aug 16, 2018 at 13:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.