Версия Google Script для VLookup (более эффективный метод?) - PullRequest
0 голосов
/ 17 февраля 2020

Я пытаюсь собрать функцию, которая позволит мне переносить информацию столбца с одного листа на другой на основе ключевого столбца. Это будет работать аналогично индексному соответствию или vlookup в excel / google.

Пример данных:

enter image description here

Что я пробовал:

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);
}

Определенные параметры

  • importFromSht - лист, из которого мы получаем значения.
  • importToSht - значения листа будут скопированы.
  • importFromCompCol - Столбец (число), в котором есть значения для сопоставления.
  • importToCompCol - Столбец (число), в котором есть значения для сопоставления.
  • importFromCol - Столбец (число), содержащий значение, которое необходимо скопировать.
  • importToCol - Столбец (число) для копирования значения в.

Требования:

  • Минимум более 6 тысяч строк и может быть намного больше тысяч. Скорость исполнения важна. Является ли мой подход правильным или есть более эффективные методы? Мой сценарий прибавил около 30 секунд ко времени выполнения.
  • Хотел бы вызвать его как функцию, поскольку я вижу себя использующим это в других областях этого проекта и других проектов.

Ответы [ 2 ]

2 голосов
/ 17 февраля 2020

Выпуск:

  • Медленный сценарий:

    • O (n 2 ): Для каждого элемента в массиве 1 массив 2 повторяется сверху вниз. Даже после нахождения совпадения в массиве 2 l oop не прерывается (break), но внутренний l oop завершается до конца массива 2 без необходимости.

    • getValues() запрашивается дважды для двух столбцов одного листа. Контакт с таблицей является дорогостоящим. Таким образом, ограничение необходимо.

Решение:

Одно возможное решение для достижения O(n):

  • Создайте новый объект, используя массив 1 с ключом в качестве «значения для поиска». Тогда можно каждый раз напрямую обращаться к значению в этом объекте для каждого значения в массиве 2.

Пример сценария:

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])));
}

Производительность:

  • ~ 5 с для 10000 строк на листе 1 и 10000 строк на листе 2

Ссылки:

0 голосов
/ 17 февраля 2020

К сожалению, я боюсь, что в Apps Script нет встроенной функции для этого.

Однако я попробовал вашу пользовательскую функцию со 100 значениями, и для ее запуска потребовалось <3 секунды. Я также запустил его с 1000 значениями, и мое время работы составило около 40 секунд. Это не идеально, но работает последовательно. Вот код, который я использовал: </p>

    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);
    }

Другой и более эффективный подход заключается в использовании IMPORTRANGE (URL первого листа) для промежуточного листа, меняющего столбцы первого лист, чтобы затем сделать VLOOKUP на вашем втором листе. Это было бы гораздо эффективнее, чем делать это в скрипте приложений, так как он не работает в памяти, и вы избегаете проблемы превышения времени выполнения пользовательской функции.

В случае, если вы хотите сохранить его в качестве пользовательской функции скрипта приложения Здесь приведены некоторые предложения по документации о том, как повысить эффективность вашей функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...