Dealing with Memory Issues in Google Apps Scripts

Currently, I am addressing a challenge within my organization that requires me to maintain some level of ambiguity. However, I have been granted permission to discuss this issue openly.

The task at hand involves creating a script to analyze a Google Sheet containing a column of numerical data. The objective is for the script to identify and return a series of ranges (specified in A1 notation) where the sum of the numerical values approximates 0.25 without exceeding it. This process should encompass all relevant ranges on the sheet. For example, given the following dataset:

A (COLUMN HEADER)
DataHeader (A1)
.1 (A2)
.01 (A3)
.04 (A4)
.1 (A5)
.03 (A6)
.02 (A7)
.1 (A8)
.05 (A9)
.04 (A10)
.07 (A11)

The expected output from the script would be [A2:A4, A5:A10, A11], since A2:A4 sums up to exactly 0.25, while A5:A10 falls just below 0.25 with the inclusion of A11 tipping the total above 0.25. Including A11 is necessary for retaining the complete dataset.

In practice, the script generates larger ranges specified in A1 notation. The main challenge I am encountering lies in constructing an accurate running total and extraction of the relevant rows.

As of now, my script comprises two functions to address separate aspects of the problem:

The initial function identifies the essential information – the dataset for analysis and the number of rows from the top of the sheet where the data begins

var data
and
var A1offset

The second function focuses on calculating the cumulative sum of the dataset array and compiling pairs of row numbers that represent ranges where the total remains slightly under 0.25. Below is the snippet causing the error:

 var result = [] //empty array to store row number pairs.
  //data is a previously obtained array of my data of interest
  //A1offset is the number of rows between the top of the sheet and the start of data
  for (var i = 0;i<data.length;i++){
      cursum += data[i][0]//add current value to cursum
    if( cursum >= .25 && result.length<1){//if we are @ the beginning add first rownum (A1 Notation) of data to result
      i=i-1 //Go back one so that i++ runs, we don't miss this datapoint.
      cursum = 0 //reset  
      result.push([(A1offset),(i + A1offset )])// 
    }
    else if( cursum >= .25 && result.length>=1){
      i=i-1//go back one
      cursum = 0//reset
      result.push([(result[result.length-1][1]+1),(i+A1offset)]) //Add to result a pair of values, the 
      //row after the end of the last range and the current row.


    }
  }

The roadblock I'm facing emerged post the addition of the i=i-1 statement. It triggers an 'Out of Memory' error when executed. Interestingly, the issue does not arise when working with a smaller dataset. Experimentally, limiting iterations to .85*data.length resolved the matter. The dataset in question contains 4978 elements.

I'm left pondering if there exists a predefined cap on the number of iterations permissible in Google scripts. Considering my limited background in computer science, any insights or suggestions on improving the code efficiency would be greatly appreciated. Please feel free to ask for additional details if needed.

You can explore a sample version of my sheet along with the full script provided below (highly commented for clarity):

function IDDATA() {
  //ID the data to sum
  var spsheet = SpreadsheetApp.getActive(); //Get spreadsheet
  var tab = spsheet.getSheetByName("Test") //Fetch data sheet
  var Drows = tab.getRange("A:A").getValues() //Capture all Column D values

  var filledvals =  Drows.filter(String).length //Identify filled rows count in Column D
  var offset = 0 //Initialize offset as 0
  var ct1 = 0 
  while(Drows[ct1][0].indexOf("DATA")<0){ 
    ct1++
  }

  offset = ct1 
  var A1offset = ct1 + 2
  var datarows = filledvals-2 

  return([datarows,offset,A1offset])
}

function RUNSUM(){
  var firstcol = "A"
  var lastcol = "A"
  var spsheet = SpreadsheetApp.getActive(); 
  var tab = spsheet.getSheetByName("Test") 
  var vararray = IDDATA()
  var len = vararray[0] 
  var offset = vararray[1] 
  var A1offset = vararray[2]
  var startrow = "A"+A1offset
  var endrow = "A"+(len+A1offset)
  var cursum = 0 
  var range = tab.getRange(startrow+":"+endrow) 
  var data = range.getValues() 

  var testmax = Math.floor(.85*data.length)

  var result = [] 

  for (var i = 0;i<.8*data.length;i++){ 
      // Data processing logic here
  }

  var rangearray = []
  var intarray = []

  for(var k = 0; k < result.length; k++){
    intarray.push([result[k][0].toFixed(0),result[k][1].toFixed(0)]) 
  }

  for (var j = 0;j<result.length;j++){
    rangearray.push(firstcol+intarray[j][0]+":"+lastcol+intarray[j][1])

  }
  Logger.log(rangearray)
  return rangearray
}

Answer №1

The provided data sheet shows that the cell 4548 contains the value 0.2584.

Your current algorithm encounters an issue where it continuously adds this outlier value to the result array, resulting in an infinite loop situation.

To address this problem, within the RUNSUM() function after the for loop declaration (

for (var i = 0;i<data.length;i++)
), you need to handle this scenario by either rectifying the data or dealing with the specific value causing the loop.

In a revised version of the algorithm below, attention has been given to handling the last range and disregarding values over 0.25 for improved clarity and stability:

function myAlgorithm() {
  var sheet = SpreadsheetApp.getActive().getSheetByName('Test');
  var values = sheet.getRange("A6:A").getValues();
  var l = 0;
  var results = []; // 1-indexed results
  var currentSum = 0;
  var offset = 5;

  for (var i=0; i<values.length && typeof values[i][0] == 'number'; i++) {
    if (values[i][0] >= 0.25) {
      Logger.log('Found value larger or equal than 0.25 at row %s', i+1+offset);
      if (l<i) {
        results.push([l+1+offset, i+offset, currentSum]);
      }
      l = i+1;
      currentSum = 0;
    } else {
      if (currentSum + values[i][0] > 0.25) {
        results.push([l+1+offset, i+offset, currentSum]);
        l = i;
        currentSum = values[i][0];
      } else {
        currentSum += values[i][0];
      }
    }
  }

  if (l<i) {
    results.push([l+1+offset, i+offset, currentSum]);
  }
  for (var i=0; i<results.length; i++) {
    Logger.log(results[i]);
  }
}

If you choose to adjust your code to handle this situation, refer to the details provided in this troubleshooting resource:

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can you please provide guidance on implementing automatic horizontal scrolling with pauses between each div?

setInterval(function scroll() { $(".box_auto").each(function(i, e) { $("html, body").animate({ scrollTop: $(e).offset().top }, 500).delay(500); }); setTimeout(function() { $('html, body').animate({ scrollTop: 0 } ...

Tips for enabling custom object properties in Chrome DevTools

In my typescript class, I am utilizing a Proxy to intercept and dispatch on get and set operations. The functionality is working smoothly and I have successfully enabled auto-completion in vscode for these properties. However, when I switch to the chrome d ...

Issues with Javascript Arrays not adding objects with duplicate values

When objects have arrays with the same values, only one of them is considered. For example: data[2018][2][25] <-- this one gets ignored by the object data[2018][2][22] Sample Code: var date = new Date(); var data = {}; <?php $eventsNum = 3> &l ...

Displaying the information from a nested array of objects in an HTML table through iteration

In the code snippet below, there is an input with a nested array of objects. The main array of objects is called summary and within it, there's a nested array called run_type. let input = { "summary": [ { " ...

Outputting an object using console.log in Node.js

When I print the error object in nodejs, the result of console.log(err) appears as follows: { [error: column "pkvalue" does not exist] name: 'error', length: 96, severity: 'ERROR'} I'm curious about the information enclosed ...

What is the proper way to input a Response object retrieved from a fetch request?

I am currently handling parallel requests for multiple fetches and I would like to define results as an array of response objects instead of just a general array of type any. However, I am uncertain about how to accomplish this. I attempted to research "ho ...

Is it accurate to categorize every ajax request (using xmlhttprequest) as a web service request?

Recently, I began incorporating AngularJS with Spring MVC as my backend. I have been utilizing $resource to connect with my backend. Given that this is a restful service and $resource operates using ajax, I find myself questioning: 1) Is ajax solely used ...

Error Encountered During JavaScript Form Validation

Currently, I am troubleshooting a website that was created by another developer. There is a form with JavaScript validation to ensure data is accurately entered into the database. However, I am puzzled as to why I keep receiving these alert messages. Pleas ...

ReactJS - When a child component's onClick event triggers a parent method, the scope of the parent method may not behave as anticipated

In my current setup, I have a parent component and a child component. The parent component contains a method within its class that needs to be triggered when the child component is clicked. This particular method is responsible for updating the store. Howe ...

JSP checkbox functionality

I have been attempting to solve this issue since last night, but I am struggling and need some help. There are two pages, named name.jsp and roll.jsp. In name.jsp, there are two input text boxes and one checkbox. After entering data in the text boxes and ...

What is the best way to include two class names within a single div using Next.js?

Struggling to include two different CSS classes into a single div element, I encountered some issues. For reference, here is a screenshot: https://i.stack.imgur.com/UuCBV.png https://i.stack.imgur.com/sHNwq.png My code snippet looks like this: blog.js ...

Angular CDKScrollable not triggering events

I'm having trouble making the angular CdkScrollable work when creating my own div: <div class="main-section" id="mainsection" #mainsection CdkScrollable> <div class="content" style="height: 300px; backgr ...

Ensuring validity with Vuelidate for customizable fields

There's a form where fields are dynamically added on a click event. I want a validation error to appear when the field value is less than 9 digits after changing or blurring it. The issue is that since the fields are created dynamically with the same ...

What is the equivalent of jQuery's blur event in AngularJS?

I need to implement a functionality in AngularJS where any opened component is closed when clicking outside of it. Is there an existing Angular directive for handling blur events, or do I need to come up with a custom solution? ...

Modal closes automatically after being clicked twice on data-bs-dismiss

Having an odd issue with Bootstrap 5.0.2 In order to close the modal, I have to double-click the button (data-bs-dismiss) It's worth noting that I use multiple modals on the page, but they only open when needed. <div class="modal" id="open-rat ...

Failed to locate lodash during npm installation

I recently set up my project by installing lodash and a few other libraries using npm: npm install grunt-contrib-jshint --save-dev npm install grunt-contrib-testem --save-dev npm install sinon --save-dev npm install -g phantomjs npm install lodash --save ...

Mobile website scroll assistant

Seeking a solution to aid mobile users in scrolling through a lengthy article page. Typically in mobile apps, an alphabetical index assists users in navigating long lists. How can I incorporate a similar feature into a webapp? For context, my tech stack i ...

Encountering an issue with Apollo Express GraphQL: Error message stating that the schema must have distinct type names, yet it contains more than one type named "DateTime"

After importing the applyMiddleware library from 'graphql-middleware' to add validation middleware on mutation's input, I created a sample middleware function that logs the input. export const logInput = async (resolve, root, args, context, ...

Passing events value in Fullcalendar Plugin by utilizing a javascript function to format events in the Fullcalendar event format

Currently, I am utilizing the full calendar plugin to display data on a calendar from a workflow. The values needed for the events are obtained in a separate function and need to be passed as fullcalendar events. I am uncertain about how to retrieve these ...

Locate Vue Components That Are Persisting

After loading my app and immediately taking a Chrome memory heap snapshot, I found the following results. https://i.stack.imgur.com/QB8u3.png Upon further exploration of my web app and then returning to the initial loaded page to take another memory heap ...