在应用程序脚本中按具有动态范围的列值将 sheet 拆分为不同的工作簿

split the sheet into different workbooks by column values with dynamic range in apps script

我想根据 A 列中的值将 google sheet 拆分到不同的工作簿中,而不是同一工作簿中的选项卡。虽然我有一个脚本可以将数据拆分到不同的工作簿中但是其中的数据范围不是动态的,就像要添加到每个工作簿中的列数是固定的一样。我希望它们是动态的,直到 数据范围 最后一列 。我已经尝试了很多通过添加循环使其动态化但它显示 The number of columns in the data does not match the number of columns in the range. The data has 1 but the range has 12. 这个错误。日志中的数据对于固定范围(工作正常)和我尝试过的动态范围几乎没有区别但不知道为什么它显示错误。已经陷进去了。任何帮助将不胜感激。

这是我正在尝试的功能。

function splitSheets() {
  var theWorkbook = SpreadsheetApp.getActiveSpreadsheet();
  var theSheet = theWorkbook.getSheetByName("Master");
  var slc = theSheet.getDataRange().getLastColumn()
  var slcv = theSheet.getRange("B1:B" + slc).getValues()
  var sheets = theWorkbook.getSheets();
  for (i = 0; i < sheets.length; i++) {
    switch(sheets[i].getSheetName()) {
      case "Master":
    break;
      default:
      theWorkbook.deleteSheet(sheets[i]);
    }
  } 
  var key = theSheet.getRange("A:A").getValues();
  var rows = theSheet.getDataRange().getValues();
  var headerFormat = theSheet.getRange("2:2").getValues();
  var folderId = '16XVypjB5_PWe2PaBIREpDGCNQlZuWL4k'
  var completedSheets = [];

  for (var i = 2; i < key.length; i++) { 
    // if(completedSheets.includes('Blank') && key[i][0] === ""){
    // }else{
    if(!completedSheets.includes(key[i][0]) ) {
      if (key[i][0] === "") {
        var name = 'Blank'
        var resource = {
          title: name,
          mimeType: MimeType.GOOGLE_SHEETS,
          parents: [{ id: folderId }]
        }
        var insertedFile = Drive.Files.insert(resource)
        var csid = insertedFile.id
        var currentSheet = SpreadsheetApp.openById(csid).getSheetByName("Sheet1")

        // var currentSheet = theWorkbook.insertSheet("Blank");
      } else {
        var name = key[i][0]
        var resource = {
          title: name,
          mimeType: MimeType.GOOGLE_SHEETS,
          parents: [{ id: folderId }]
        }
        var insertedFile = Drive.Files.insert(resource)
        var csid = insertedFile.id
        var currentSheet = SpreadsheetApp.openById(csid).getSheetByName("Sheet1")

        // var currentSheet = theWorkbook.insertSheet(key[i][0]);
      }

      var theNewRows =[];
      var b=0;

      for(var j = 1; j < rows.length; j++) {
        var rown = []
        for(var c = 0; c < slcv.length; c++){

          // some other trials
          // if((rows[j][0] == key[i][0]) || (rows[j][0] === '' && currentSheet.getName() == "Blank")){
          //   theNewRows[b]=[];
          //   theNewRows[b].push (
          //     rows[j][c].toString()
        
              // This although adds the data and range dynamically but also shows the mentioned error.
              rown.push(rows[j][c])
            // );
          //   b++;
          // }
        }

        if((rows[j][0] == key[i][0]) || (rows[j][0] === '' && currentSheet.getName() == "Blank")){
          theNewRows[b]=[];
          theNewRows[b].push (
            rown.toLocaleString()
          
            // These are the fixed column for data rnage
            // rows[j][0],rows[j][1],rows[j][2],rows[j][3],rows[j][4],rows[j][5],rows[j][6],rows[j][7],rows[j][8],rows[j][9],rows[j][10],rows[j][11]
            );
          b++;
        }
        Logger.log(rown)
      }
      Logger.log(theNewRows)
      // Logger.log(theNewRows)
      currentSheet.getRange("1:1").setValues(headerFormat)
      var outrng = currentSheet.getRange(2,1,theNewRows.length, slc);//Make the output range the same size as the output array
      outrng.setValues(theNewRows);
      currentSheet.autoResizeColumns(1, slc);
      if(currentSheet.getSheetName() == 'Blank') {
      completedSheets.push('Blank');
      last = "Blank";
      }else{
      completedSheets.push(key[i][0])
      last = key[i][0]
      // }
    }
    }
  }
  SpreadsheetApp.setActiveSheet(theWorkbook.getSheetByName('Master'));
}

我彻底检查并改进了您的脚本,使其更具可读性,并且通过使用数组方法来减少 Spreadsheet 调用。

脚本:

function splitSheets() {
  var folderId = '*** FOLDER ID ***';
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheets = spreadsheet.getSheets();
  var sheet = spreadsheet.getSheetByName('Master');
  // delete sheets that are not named 'Master'
  sheets.forEach(sheetIter => {
    if(sheetIter.getSheetName() != 'Master')
      spreadsheet.deleteSheet(sheetIter);
  });
  var data = sheet.getDataRange().getValues();
  // remove 1st row (blank row)
  data.shift();
  // remove 2nd row from data and assign as headers
  var headers = data.shift();
  // get unique list of sheet names from column A
  var sheetNames = data.map(row => row[0]).filter(onlyUnique);
  // loop those unique sheetNames
  sheetNames.map(sheetName => {
    // filter data by getting only rows with same column A and sheetName
    var outputData = data.filter(row => row[0] == sheetName);
    // add header from data filtered
    outputData.unshift(headers);

    var resource = {
      title: sheetName || 'Blank',
      mimeType: MimeType.GOOGLE_SHEETS,
      parents: [{ id: folderId }]
    }

    var file = Drive.Files.insert(resource);
    var currentSheet = SpreadsheetApp.openById(file.id).getSheetByName('Sheet1');
    // write data filtered with the header
    currentSheet.getRange(1, 1, outputData.length, outputData[0].length).setValues(outputData);
    // resize the columns
    currentSheet.autoResizeColumns(1, outputData[0].length);
  });
}

// function to get unique values from array using filter
function onlyUnique(value, index, self) {
  return self.indexOf(value) === index;
}

示例输出: