Home > Software engineering >  Brute force code to merge intervals - Google sheets appscript
Brute force code to merge intervals - Google sheets appscript

Time:02-17

I need a bruteforce code in appscript to merge the intervals into one or more intervals that contain all the ranges for an specific ID. I'm already working on it but in the actual state i cannot program in appscript and i'm hoping to get this task done as soon as possible.

Example: for ID 11403

{43896,44463} 
{44245,44245}
{44257,44257}
{44258,44258}
{44258,44258}
{44265,44316}
{44271,44271}
{44277,44279}
{44300,44326}
{44363,44363}
{44363,44363}
{44376,44376}
{44265,44316}
{44271,44271}
{44410,44410}
{44537,44537}
{44540,44553}
{44544,44547}

The results must be:

{43896,44410}
{44537,44537}
{44540,44553}

Sheet of use: https://docs.google.com/spreadsheets/d/1UR0xgjCHVxE2Vt0-teSK25f-Kej14Kwfhu5hyhXbDNg/edit?usp=sharing

CodePudding user response:

Suppose your table looks like this:

ID start end
11403 43896 44463
11403 44245 44245
11403 44257 44257
11403 44258 44258
11403 44258 44258
11403 44265 44316
11403 44271 44271
11403 44277 44279
11403 44300 44326
11403 44363 44363
11403 44363 44363
11403 44376 44376
11403 44265 44316
11403 44271 44271
11403 44410 44410
11403 44537 44537
11403 44540 44553
11403 44544 44547
12345 43896 44463
12345 44245 44245
12345 44257 44257

Here is the code:

function myFunction() {
  var sh = SpreadsheetApp.getActiveSheet();
  var data = sh.getRange('A2:C').getValues();

  var obj = {}
  while (data.length) {
    var [key, start, end] = data.shift();
    var range = {'start': start, 'end': end};
    try { obj[key].push(range) } catch(e) { obj[key] = [range] };
  }

  var ranges = merge_ranges(obj['11403']); // get the merged ranges for id 11403

  console.log(ranges); // <-------- here are the results (for id 11403)
}


function merge_ranges(obj) {
  var range = obj.shift();
  var end = range.end;
  var ranges = [range];
    
  while (obj.length) {
    var range = obj.shift();
    if (range.start > end) {
      ranges.push(range)
      if (range.end > end) end = range.end;
    }
  }
  return ranges;
}

From your data it gives the array of ranges:

[ { start: 43896, end: 44463 },
  { start: 44537, end: 44537 },
  { start: 44540, end: 44553 } ]

They look quite close to your results.

But it's not clear from your question what exactly you want to do with these results. Loop through all the IDs an put on the sheet?

Update

Probably it should be something like this:

function myFunction() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sh = ss.getSheetByName('Página1'); // <----- a name of the source sheet
  var data = sh.getRange('A2:C').getValues();

  // create the object {id1: [range, range, range], id2: [range], ...}
  var obj = {}
  while (data.length) {
    var [id, start, end] = data.shift();
    var range = {'start': start, 'end': end};
    try { obj[id].push(range) } catch(e) { obj[id] = [range] };
  }

  // make the table from the object [id, range.start, range.end]
  var table = [];
  for (var id in obj) {
    var ranges = merge_ranges(obj[id]);
    ranges.forEach(range => table.push([id, range.start, range.end]));
  }
  
  // create or select the sheet 'Output'
  try { var output = ss.getSheetByName('Output'); output.clear(); }
  catch(e) { var output = ss.insertSheet(); output.setName('Output') }

  // add the header to the table and put the table on the sheet
  var header = ['ID', 'Start', 'End'];
  table = [header, ...table];
  var range = output.getRange(1, 1, table.length, table[0].length);
  range.setValues(table);
}

function merge_ranges(obj) {
  var range = obj.shift();
  var end = range.end;
  var ranges = [range];
    
  while (obj.length) {
    var range = obj.shift();
    if (range.start > end) {
      ranges.push(range)
      if (range.end > end) end = range.end;
    }
  }
  return ranges;
}

It puts the results as a plain 3-colon table on the sheet 'Output'.

  • Related