Google App Script для копирования строк в динамически создаваемые вкладки на основе значения столбца - PullRequest
0 голосов
/ 23 января 2020

Во-первых, я учитель и самостоятельно обучаю себя скриптам приложений, поэтому, пожалуйста, прости мой неаккуратный код. Результаты частых стандартизированных тестов моего округа часто предоставляются со всеми тестами, объединенными в один лист. Им было бы намного легче управлять, если бы каждый тест был в их собственных листах.

Я изменил функцию, найденную на этом сайте, чтобы создать одну новую вкладку для каждого уникального значения в тестовом столбце (M). Это заботится о наличии вкладок для копирования строк. Он использует массив, и я, честно говоря, не понимаю его полностью.

function createNewSheets() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var masterSheet = spreadsheet.getSheetByName('Sheet1');
  var source_range = masterSheet.getRange("A1:AD1"); //header row

  // Retrieve 2d array for column M
  var colA = masterSheet.getRange('M2:M').getValues();

  // Create a 1d array of unique values
  var uniqueValues = {};
  colA.forEach(function(row) {
    row[0] ? uniqueValues[row[0]] = true : null;
  });
  var newSheetNames = Object.keys(uniqueValues);

  newSheetNames.forEach(function(sheetName) {
    // Check to see whether the sheet already exists
    var sheet = spreadsheet.getSheetByName(sheetName);
    if (!sheet) {
      spreadsheet.insertSheet(sheetName); //inserts new sheet
      source_range.copyTo(spreadsheet.getSheetByName(sheetName).getRange("A1:AD1")); //writes header row to newly created sheet
    }
  });
}

Чтобы получить правильные строки в соответствующих вкладках, я использовал операторы if if. Однако это означает, что я должен предвидеть все различные вкладки, которые будут созданы первой функцией, а затем изменить свой код перед его запуском. Это также довольно медленно, но терпимо. Хотя это работает, имеет , чтобы быть лучше. Если у кого-то есть какие-либо предложения, я буду очень признателен.

function copyRows() {
  var sSheet = SpreadsheetApp.getActiveSpreadsheet();
  var srcSheet = sSheet.getSheetByName("Sheet1"); 
  var lastRow = srcSheet.getLastRow();

  for (var i = 2; i <= lastRow; i++) {
    var srcRange = srcSheet.getRange("A" + i + ":AD" + i);
    var cell = srcSheet.getRange("M" + i);
    var val = cell.getValue();

  //sets the target sheet depending on the exam in column M

    if (val == "Growth: Language 2-12 KS 2017") {
      var tarSheet = sSheet.getSheetByName("Growth: Language 2-12 KS 2017");
    }

    else if (val == "Growth: Math 2-5 KS 2017") {
      var tarSheet = sSheet.getSheetByName("Growth: Math 2-5 KS 2017");
    }  

    else if (val == "Growth: Reading 2-5 KS 2017") {
      var tarSheet = sSheet.getSheetByName("Growth: Reading 2-5 KS 2017");
    } 

    else if (val == "Growth: Reading K-2 KS 2017") {
      var tarSheet = sSheet.getSheetByName("Growth: Reading 2-5 KS 2017");
    } 

    else if (val == "Growth: Math K-2 KS 2017") {
      var tarSheet = sSheet.getSheetByName("Growth: Reading 2-5 KS 2017");
    } 

    else {
    }
  //insets the row in the correct target worksheet  
      var tarRow = tarSheet.getLastRow()+1;
      tarSheet.insertRows(tarRow);
      var tarRange = tarSheet.getRange("A" + (tarRow) + ":AD" + (tarRow));
      srcRange.copyTo(tarRange);    
  }
};

Вот ссылка на лист с фиктивными данными. Мои настоящие листы могут содержать от 1500 до 2000 строк с 8 или более тестами.

Ответы [ 2 ]

0 голосов
/ 23 января 2020

Если я вас правильно понимаю, вам нужна функция, которая:

  • Создает новый лист для каждого отдельного Assessment Name (столбец M из Sheet1).
  • Добавляет строки, соответствующие каждому Assessment Name, к соответствующему созданному листу.

Если это так, то вы можете перебрать все данные в Sheet1, и для каждой строки проверьте, есть ли лист в электронной таблице, имя которого совпадает с соответствующим именем оценки.

Если такой лист существует, скрипт добавляет текущую строку в конец целевого листа.

Если лист не существует, он сначала создает этот лист с верхними заголовками, а затем добавляет текущую строку.

Это достигается использованием appendRow(rowContents).

Ваш код может выглядеть следующим образом:

function createNewSheets() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var masterSheet = spreadsheet.getSheetByName('Sheet1');
  // Get range with data from original sheet:
  var firstRow = 1;
  var firstCol = 1;
  var numRows = masterSheet.getLastRow();
  var numCols = masterSheet.getLastColumn();
  var data_range = masterSheet.getRange(firstRow, firstCol, numRows, numCols).getValues();
  // Get headers row (to be appended on top when new sheet is created):
  var headers = data_range[0];
  // Iterate through all rows of data from Sheet1:
  for (var i = 1; i < data_range.length; i++) {
    var row = data_range[i]; // Current row
    var assessmentName = row[12]; // Assessment name
    // Get sheet with current assessment name:
    var sheet = spreadsheet.getSheetByName(assessmentName);
    // Check if sheet with current assessment name exists. If it doesn't it creates it:
    if (!sheet) {
      sheet = spreadsheet.insertSheet(assessmentName);
      sheet.appendRow(headers);
    }
    // Appends current row of data to the new sheet:
    sheet.appendRow(row);
  }
}

Кроме того, если вы хотите избежать дублирования строк, добавляемых при каждом запуске скрипта, вы можете столбец в последнем столбце основного листа, который отслеживает, какие строки были скопированы на новый лист, и, если они были скопированы, избегайте добавления их снова. Например, вы можете иметь заголовок столбца в AC с именем Copied. Затем, когда строка добавляется, эта строка заполняется, например, строкой «Готово». При следующем запуске сценария он может проверить, имеет ли соответствующая ячейка значение «Готово».

Вы можете, например, изменить конец функции следующим образом:

    // Appends current row of data to the new sheet:
    sheet.appendRow(row);
  }
}

На это:

    // Appends current row of data to the new sheet if `AC` column value is not "Done":
    if (row[28] != "Done") {
      sheet.appendRow(row);
      masterSheet.getRange(i + 1, 29).setValue("Done");    
    }
  }
}

Я надеюсь, что это поможет .

0 голосов
/ 23 января 2020

Эта функция может заменить ваш скрипт копирования строк, и он должен работать значительно быстрее.

function copySheets() {
  var keyA=["Growth: Language 2-12 KS 2017", "Growth: Math 2-5 KS 2017", "Growth: Reading 2-5 KS 2017", "Growth: Reading K-2 KS 2017", "Growth: Math K-2 KS 2017"];
  var shtA=["Growth: Language 2-12 KS 2017", "Growth: Math 2-5 KS 2017", "Growth: Reading 2-5 KS 2017", "Growth: Reading K-2 KS 2017", "Growth: Math K-2 KS 2017"];
/*
I made the above arrays to different one in the event that you ever wish to change the mapping.

The code below gets all of the data on the source sheet from column1 to column 30 and row 2 to the last row.  Whenever you have a startrow that is not 1 you need to subtracting off the rows above the start row from the sheet.getLastRow() because the third parameter for get range is not the last row but the number of rows.

This code get all of the data in one two dimensional array and sticks it into the target range all at one time.  In my experience you should see a 10x increase in performance.
*/
  var ss=SpreadsheetApp.getActive();
  var srcsh=ss.getSheetByName("Sheet1"); 
  var vA=srcsh.getRange(2,1,srcsh.getLastRow()-1,30).getValues();
  var keyToSheet={};
  keyA.forEach(function(key,i){keyToSheet[key]=shtA[i];})
  var tarsh=ss.getSheetByName(keyToSheet(val));
  var tarrg=tarsh.getRange(2,1,vA.length,vA[0].length).setValues(vA);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...