Google Script version of VLookup (More Efficient Method?)

喜夏-厌秋 提交于 2021-02-05 12:24:55

问题


I'm trying to put together a function that will allow me to pull a column's info from one sheet to another based on a key column. This would work similar to an index match or vlookup in excel/google.

Sample Data:

What I've tried:

function vlookup(importFromSht, importToSht, importFromCompCol, importToCompCol,importFromCol, importToCol){
  var lastImportFromRN = importFromSht.getLastRow();
  var lastImportToRN = importToSht.getLastRow();
  var importFromCompArr =  importFromSht.getRange(2, importFromCompCol, lastImportFromRN, 1).getValues();
  var importToCompArr =  importToSht.getRange(2, importToCompCol, lastImportToRN, 1).getValues();
  var importFromArr =  importFromSht.getRange(2, importFromCol, lastImportFromRN, 1).getValues();
  var importToArr = [];

  for (var i in importToCompArr) {
    for (var j in importFromCompArr){
      if (importToCompArr[i].toString() == importFromCompArr[j].toString()) { 
        importToArr.push(importFromArr[j]);
      }
    }
  }

  //Paste to column
  importToSht.getRange(2,importToCol,importToArr.length,1).setValues(importToArr);
}

Parameters Defined

  • importFromSht - Sheet we are grabbing values from.
  • importToSht - Sheet values will be copied to.
  • importFromCompCol - Column (number) that has values to match on.
  • importToCompCol - Column (number) that has values to match on.
  • importFromCol - Column (number) that contains value that needs to be copied.
  • importToCol - Column (number) to copy value to.

Requirements:

  • There are over 6K rows minimum and could be many more thousand. Speed of execution is important. Is my approach the correct approach or are there more efficient methods? My script added about 30 seconds to my execution time.
  • Would like to call it as a function as I can see myself using this in other areas of this projects and other projects.

回答1:


Issue:

  • Slow script:

    • O(n2): For every element in array 1, the array 2 is iterated from top to bottom. Even after finding a match in array 2, the loop is not broken(break), but the inner loop is completed until the end of the array2 unnecessarily.

    • getValues() is requested twice for two columns of the same sheet. Contact with spreadsheet is costly. So, limiting it is necessary.

Solution:

One possible solution to achieve O(n):

  • Create a new object using array 1 with key as 'the value to look for'. Then it's possible to directly access the value in this object each time for each value in array 2.

Sample script:

const ss = SpreadsheetApp.getActive();
/**
 * @param {GoogleAppsScript.Spreadsheet.Sheet} fromSht -Sheet to import from
 * @param {GoogleAppsScript.Spreadsheet.Sheet} toSht -Sheet to import to
 * @param {Number} fromCompCol -Column number of fromSht to compare
 * @param {Number} toCompCol -Column number of toSht to compare
 * @param {Number} fromCol -Column number of fromSht to get result
 * @param {Number} toCol -Column number of toSht to get result
 */
function vlookup_2(
  fromSht = ss.getSheetByName('Sheet1'),
  toSht = ss.getSheetByName('Sheet2'),
  fromCompCol = 1,
  toCompCol = 1,
  fromCol = 2,
  toCol = 2
) {
  const toShtLr = toSht.getLastRow();
  const toCompArr = toSht.getRange(2, toCompCol, toShtLr - 1, 1).getValues();
  const fromArr = fromSht.getDataRange().getValues();
  fromCompCol--;
  fromCol--;

  /*Create a hash object of fromSheet*/
  const obj1 = fromArr.reduce((obj, row) => {
    let el = row[fromCompCol];
    el in obj ? null : (obj[el] = row[fromCol]);
    return obj;
  }, {});

  //Paste to column
  toSht
    .getRange(2, toCol, toShtLr - 1, 1)
    .setValues(toCompArr.map(row => (row[0] in obj1 ? [obj1[row[0]]] : [null])));
}

Performance:

  • ~5s for 10000 rows in sheet1 and 10000 rows in sheet 2

References:

  • Time complexity
  • Hash map



回答2:


Unfortunately I am afraid there is no built-in function for this in Apps Script.

However, I have tried your custom function with 100 values and it took <3 seconds to run. I also ran it with 1000 values and my running time was around 40 seconds. It is not ideal but it works consistently. Here is the code I have used:

    var sheet = SpreadsheetApp.getActiveSpreadsheet();
    var importFromSht = SpreadsheetApp.getActive().getSheetByName('Sheet1'); //sheet we are grabbing the values of
    var importToSht = SpreadsheetApp.getActive().getSheetByName('Sheet2');  //sheet we are pasting our values
    var importFromCompCol = 2; // Column (number) that has values to match on.
    var importToCompCol = 2; // Column (number) that has values to match on.
    var importFromCol = 1; // Column (number) that contains value that needs to be copied.
    var importToCol = 1; // Column (number) to copy value to.
    
    function customVlookup (){
      var lastImportFromRN = importFromSht.getLastRow();
      var lastImportToRN = importToSht.getLastRow();
      var importFromCompArr =  importFromSht.getRange(1, importFromCompCol, lastImportFromRN, 1).getValues();
      var importToCompArr =  importToSht.getRange(1, importToCompCol, lastImportToRN, 1).getValues();
      var importFromArr =  importFromSht.getRange(1, importFromCol, lastImportFromRN, 1).getValues();
      var importToArr = [];
    
      for (var i in importToCompArr) {
        for (var j in importFromCompArr){
          if (importToCompArr[i].toString() == importFromCompArr[j].toString()) { 
            importToArr.push(importFromArr[j]);
          }
        }
      }
      //Paste to column
      importToSht.getRange(1,importToCol,importToArr.length,1).setValues(importToArr);
    }

A different and more efficient approach is to use IMPORTRANGE(URL of first sheet) to an intermediate sheet swapping the columns of the first sheet to then do a VLOOKUP on your second sheet. This would be way more efficient than doing it in Apps Script as it does not run in the memory and you avoid the issue of exceeding the execution time of a custom function.

In case you want to keep it as an Apps Script custom function Here are some suggestions on the documentation on how to improve your function’s efficiency.



来源:https://stackoverflow.com/questions/60255775/google-script-version-of-vlookup-more-efficient-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!