Better/faster 将 50 多个值从一个 Google sheet 传递到另一个的方法

Better/faster way to pass 50+ values from one Google sheet to another

我是 App Script 的新手,请原谅我的无知。

我用来保存学生数据的 Google sheet 又长又笨重(超过 50 列),所以我决定创建另一个 sheet 作为前端用于数据输入。通过数小时的教程视频 + 反复试验,我想出了一个工作脚本,它从我的数据输入表单中获取值,如 sheet ('Students') 并将这些值传递给第一个空值在我的 destination/container sheet ('Master').

我对脚本的工作方式非常满意 - 除了它慢得离谱之外。根据我读过的内容,我认为我对表格 API 的调用过多,我需要弄清楚如何将所有值从 'Students' 传递到 'Master'整体而不是一个一个,但我没有这样做的技能,而且我似乎找不到一个例子。

我确信有一个非常简单、优雅的解决方案。有人可以帮忙吗?

这是我的一小段代码(希望足以看出我使用的低效策略):

function submitStudentData(){
var caseloadManager = SpreadsheetApp.getActiveSpreadsheet();
var enterStudents = caseloadManager.getSheetByName('Students');
var masterSheet = caseloadManager.getSheetByName('Master');
var clearFields = enterStudents.getRangeList(['C6:C18', 'C22', 'E6:E18','G6:G14','G20','I6:I14','K6:K16', 'M6:M18']);
var blankRow = masterSheet.getLastRow()+1;

  masterSheet.getRange(blankRow,1).setValue(enterStudents.getRange("Z1").getValue()); //Concatenated Student Name
  masterSheet.getRange(blankRow,3).setValue(enterStudents.getRange("C6").getValue()); //First Name
  masterSheet.getRange(blankRow,2).setValue(enterStudents.getRange("C8").getValue()); //Last Name
  masterSheet.getRange(blankRow,4).setValue(enterStudents.getRange("C10").getValue()); //Goes By
  masterSheet.getRange(blankRow,6).setValue(enterStudents.getRange("E6").getValue()); //DOB
  masterSheet.getRange(blankRow,7).setValue(enterStudents.getRange("E8").getValue()); //Grade
  masterSheet.getRange(blankRow,5).setValue(enterStudents.getRange("E10").getValue()); //Student ID
  masterSheet.getRange(blankRow,10).setValue(enterStudents.getRange("E14").getValue()); //Last FIE
  masterSheet.getRange(blankRow,11).setValue(enterStudents.getRange("Z2").getValue()); //Calculated FIE Due Date
  masterSheet.getRange(blankRow,8).setValue(enterStudents.getRange("E12").getValue()); //Last Annual Date[enter image description here][1]
  masterSheet.getRange(blankRow,13).setValue(enterStudents.getRange("G6").getValue()); //PD
  masterSheet.getRange(blankRow,14).setValue(enterStudents.getRange("G8").getValue()); //SD
  masterSheet.getRange(blankRow,15).setValue(enterStudents.getRange("G10").getValue()); //TD
  masterSheet.getRange(blankRow,16).setValue(enterStudents.getRange("G3").getValue()); //Concatenated Disabilities
  masterSheet.getRange(blankRow,18).setValue(enterStudents.getRange("G12").getValue()); //Program Type
  masterSheet.getRange(blankRow,12).setValue(enterStudents.getRange("G14").getValue()); //Evaluation Status
  masterSheet.getRange(blankRow,20).setValue(enterStudents.getRange("I6").getValue()); //DYS
  masterSheet.getRange(blankRow,21).setValue(enterStudents.getRange("I8").getValue()); //GT
   masterSheet.getRange(blankRow,19).setValue(enterStudents.getRange("I10").getValue()); //EB
  masterSheet.getRange(blankRow,24).setValue(enterStudents.getRange("I12").getValue()); //ESY
  masterSheet.getRange(blankRow,22).setValue(enterStudents.getRange("I14").getValue()); //BIP
  masterSheet.getRange(blankRow,29).setValue(enterStudents.getRange("K6").getValue()); //TR
  masterSheet.getRange(blankRow,30).setValue(enterStudents.getRange("K8").getValue()); //OT

它继续,在清除 'Students.' 中的所有字段之前,像这样有 52 个值 它有效,但 运行.

需要一分钟多的时间

我正在尝试附上我的 'Students' 形式的图片 sheet 以防我的描述不清楚。

非常感谢您帮助一位不知道自己在做什么的谦虚的特殊教育工作者。 :)

Image of 'Students' form/sheet

阅读 best practices 即使您的数据不是一个连续的范围,它也是一个范围的一部分,因此使用 getValues() 获取整个范围并使用适当的索引来访问您想要的范围。最后如果会快很多。您可能不想使用 setValues 来写入数据,因为有其他问题,例如弄乱公式。尽可能避免使用 setValue() 和 getValue()

function submitStudentData() {
  const ss = SpreadsheetApp.getActive();
  const ssh = ss.getSheetByName('Students');
  const msh = ss.getSheetByName('Master');
  const nr = msh.getLastRow() + 1;
  const vs = ssh.getRange(nr, 1, ssh.getLastRow(), ssh.getLastColumn()).getValues();
  let oA1 = [[vs[0][25], vs[7][2], vs[5][2], vs[9][2], vs[9][4], vs[5][4], vs[7][4], vs[11][4]]];
  msh.getRange(msh.getLastRow() + 1, 1, oA1.length, oA[0].length).setValues(oA1);//This line replaces all of the below lines

  msh.getRange(nr, 1).setValue(vs[0][25]);//Concatenated Student Name
  msh.getRange(nr, 2).setValue(vs[7][2]); //Last Name
  msh.getRange(nr, 3).setValue(vs[5][2]); //First Name
  msh.getRange(nr, 4).setValue(vs[9][2]); //Goes By
  msh.getRange(nr, 5).setValue(vs[9][4]); //Student ID
  msh.getRange(nr, 6).setValue(vs[5][4]); //DOB
  msh.getRange(nr, 7).setValue(vs[7][4]); //Grade
  msh.getRange(nr, 8).setValue(vs[11][4]); //Last Annual Date[enter image description here][1]

您也可以通过使用公式将所有数据映射到一行或一列中来做类似的事情,从而更容易 运行 脚本。

正如 Cooper 所说,您希望尽可能避免读写 sheet(s)。 (我在开始使用 Google 脚本时遇到了同样的问题)

这意味着您应该将整个范围读入一个变量,然后将您的行写出到主控 sheet。

下面是您可以用来避免 setValue() 和 getValue() 运行缓慢的示例

function submitStudentData(){
var caseloadManager = SpreadsheetApp.getActiveSpreadsheet();
var enterStudents = caseloadManager.getSheetByName('Students');
var masterSheet = caseloadManager.getSheetByName('Master');
var clearFields = enterStudents.getRangeList(['C6:C18', 'C22', 'E6:E18','G6:G14','G20','I6:I14','K6:K16', 'M6:M18']);
var blankRow = masterSheet.getLastRow()+1; //You will not need this


//First we will all the data from the students sheet. This will make and array of arrays [[row],[row],[row]]. 
studentData = enterStudents.getRange(1,1,enterStudents.getLastRow(),enterStudents.getLastColumn()).getValues()
Logger.log(studentData)
//We are going to build an array of arrays of the data that we want to write back to the master sheet. We will start by creating our first array
writeData = []
//Then we loop through all the student data
for (var i = 0; i < studentData.length; i++) { 
  Logger.log(studentData[i][0])
  //We are selecting data from each row to add to our array. in "studentData[i][0]" the [0] is the column number (remember we are starting with 0)
  rowData = []
  rowData.push(studentData[i][0])
  rowData.push(studentData[i][2])
  rowData.push(studentData[i][1])
  //Then we send the full row to the first array we made
  writeData.push(rowData)

}


Logger.log(writeData)
// Now to write out the data. Normally it would not be a good idea to loop a write like this but this as an atomic operation that google will automatically batch write to the sheet. 
for (var i = 0; i < writeData.length; i++) { 
  masterSheet.appendRow(writeData[i])
}

}

希望这有助于您入门。

这是工作示例。只需按照代码中的要求完成 mapping 数组即可。运行时间低于 1 秒。

const mapping= [
  // enter the array [ sourceRange, destinationRow ] for each cell you want to copy form Students to Master
  ['Z1',1],
  ['C6',3],
  ['C8',2],
  ['C10',4],
  ['E6',6]
  // ... and so on
]

function submitStudentData() {
  console.time('submitStudentData')
  const caseloadManager = SpreadsheetApp.getActive();
  const enterStudents = caseloadManager.getSheetByName('Students');
  const masterSheet = caseloadManager.getSheetByName('Master');
  const data = enterStudents.getDataRange().getValues()
  const destRow = []

  mapping.forEach((m,i)=>{
    [rowi,coli] = rangeToRCindex(m[0])
    const destRowIndex = m[1] - 1
    destRow[destRowIndex] = data[rowi][coli]
  })

  masterSheet.appendRow(destRow)
  console.timeEnd('submitStudentData')
}

function rangeToRCindex(range){
  const match = range.match(/^([A-Z]+)(\d+)$/)
  if (!match) {
    throw new Error(`invalid range ${range}`)
  }
  const col = letterToColumn(match[1])
  const row = match[2]
  return [row-1,col-1]
}

function letterToColumn(columnLetters) {
  let cl = columnLetters.toUpperCase()
  let col = 0
  for (let i = 0; i < cl.length; i++) {
    col *= 26
    col += cl.charCodeAt(i) - 65 + 1
  }
  return col
}