开发者问题收集

Google Sheet Script - 如果找到单元格值,则返回标题值

2017-05-22
2528

提前感谢您的帮助。

我有一个 Google 表格,其中包含第一行的标题值。我有一个脚本,可以逐行查看表格的其余部分,如果单元格是某种颜色,则脚本会进行计数。最后,如果计数数字大于我在表格中设置的变量,则脚本将触发电子邮件。

我想尝试做的是,如果脚本找到具有设置颜色的单元格,是否还要捕获列标题值?我确信我需要创建一个包含标题值的数组,然后比较位置,但我不知道如何有效地做到这一点。

function sendEmails() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var dataSheet = ss.getSheets()[0];
  var lastRow = dataSheet.getLastRow();
  var lastColumn = dataSheet.getLastColumn();

  //Project Range Information
  var projectRange = dataSheet.getRange(6,3,lastRow-5,lastColumn);
  var projectRangeValues = projectRange.getValues()[0];
  var cellColors = projectRange.getBackgrounds();

  //Student Information Range 
  var studentRange = dataSheet.getRange(6,1,lastRow-5,lastColumn);
  var studentRangeValues = studentRange.getValues();

  //Pull email template information
  var emailSubject = ss.getRange("Variables!B1").getValue(); 
  var emailText = ss.getRange("Variables!B2").getValue();
  var triggerValue = ss.getRange("Variables!B4").getValue();
  var ccValue = ss.getRange("Variables!B5").getValue();

  //Where to Start and What to Check
  var colorY = ss.getRange("Variables!B6").getValue(); 
  var count = 0;
  var startRow = 6;

  //Loop through sheet and pull data
  for(var i = 0; i < cellColors.length; i++) {  
    //Pull some information from the rows to use in email
    var studentName = studentRangeValues[i][0];
    var studentBlogUrl = studentRangeValues[i][1];
    var studentEmail = studentRangeValues[i][2];
    var studentData = [studentName,studentBlogUrl];

    //Loop through cell colors and count them
    for(var j = 0; j < cellColors[0].length ; j++) { 
      if(cellColors[i][j] == colorY) { 

           /*This is where I feel I need to add the array comparisons to get the header values */

           count = count + 1;
      };//end if statement
    };//end for each cell in a row

    //If the count is greater than trigger, send emails
    if (count >= triggerValue) {
        //A call to another function that merges the information              
        var emailBody = fillInTemplateFromObject(emailText, studentData);
        MailApp.sendEmail({
          to: studentEmail,
          cc: ccValue,
          subject: emailSubject,
          htmlBody: emailBody,
        });
    } else {};
    //reset count to 0 before next row
    count = 0;
  };//end for each row
};

编辑: 我已根据响应更新了上述代码部分:

//Header Information
var headers = dataSheet.getRange(4,4,1,lastColumn);
var headerValues = headers.getValues();
var missingAssignments = new Array();

在 for 循环中我添加了:

//Loop through cell colors and count them
for(var j = 0; j < cellColors[0].length ; j++) { 
  if(cellColors[i][j] == colorY) {
       //This pushes the correct information into the array that matches up with the columns with a color.
       missingAssignments.push(headervalues[i][j]);
       count = count + 1;
  };//end if statement
};//end for each cell in a row

我遇到的问题是出现错误 - TypeError:无法从未定义读取属性“2”。这是由于脚本移动到下一行时 for 循环中的推送导致的。我不确定为什么会出现此错误。从我读过的其他内容来看,数组设置为未定义。我尝试将数组设置为空并将其长度设置为 0,但这没有帮助。我认为我不明白数组在运行时的作用域。

编辑: 搞清楚了,“i”不应该迭代。它应该是:

missingAssignments.push(headervalues[0][j]);

第一个 for 循环结束时,我清除了下一行的数组。

missingAssignments.length = 0;
2个回答

您应该获取整个工作表的值。然后使用 shift 方法仅获取标题。如果没有有关工作表的更多信息,我很难完全理解您的意图。如果我可以提供更多信息,请告诉我。

function sendEmails() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var dataSheet = ss.getSheets()[0];
  var lastRow = dataSheet.getLastRow();
  var lastColumn = dataSheet.getLastColumn();
  //below gets the whole sheet and shifts off the first row as headers
  var fullSheet = dataSheet.getDataRange().getValues();
  var headers = fullSheet.shift();

  //then in your loops you can check against the index of the headers array
Jordan Rhea
2017-05-22

使用 Apps 脚本生成电子表格的速度非常慢,尤其是在需要读取大量数据的情况下。

请查看这些 来自 Apps 文档的提示

使用批处理操作

Scripts commonly need to read in data from a spreadsheet, perform calculations, and then write out the results of the data to a spreadsheet. Google Apps Script already has some built-in optimization, such as using look-ahead caching to retrieve what a script is likely to get and write caching to save what is likely to be set.

You can write scripts to take maximum advantage of the built-in caching, by minimizing the number of reads and writes. Alternating read and write commands is slow. To speed up a script, read all data into an array with one command, perform any operations on the data in the array, and write the data out with one command.

Here's an example — an example you should not follow or use. The Spreadsheet Fractal Art script in the Gallery (only available in the older version of Google Sheets) uses the following code to set the background colors of every cell in a 100 x 100 spreadsheet grid:

// DO NOT USE THIS CODE. It is an example of SLOW, INEFFICIENT code.
// FOR DEMONSTRATION ONLY
var cell = sheet.getRange('a1');
for (var y = 0; y < 100; y++) {
  xcoord = xmin;
  for (var x = 0; x < 100; x++) {
    var c = getColor_(xcoord, ycoord);
    cell.offset(y, x).setBackgroundColor(c);
    xcoord += xincrement;
  }
  ycoord -= yincrement;
  SpreadsheetApp.flush();
}

The script is inefficient: it loops through 100 rows and 100 columns, writing consecutively to 10,000 cells. The Google Apps Script write-back cache helps, because it forces a write-back using flush at the end of every line. Because of the caching, there are only 100 calls to the Spreadsheet.

But the code can be made much more efficient by batching the calls. Here's a rewrite in which the cell range is read into an array called colors, the color assignment operation is performed on the data in the array, and the values in the array are written out to the spreadsheet:

// OKAY TO USE THIS EXAMPLE or code based on it.
var cell = sheet.getRange('a1');
var colors = new Array(100);
for (var y = 0; y < 100; y++) {
  xcoord = xmin;
  colors[y] = new Array(100);
  for (var x = 0; x < 100; x++) {
    colors[y][x] = getColor_(xcoord, ycoord);
    xcoord += xincrement;
  }
  ycoord -= yincrement;
}

  sheet.getRange(1, 1, 100, 100).setBackgroundColors(colors); 

inefficient code takes about 70 seconds to run. The efficient code runs in just 1 second!

If you're looking at the Spreadsheet Fractal Art script (only available in the older version of Google Sheets), please be aware that we made a minor change to it to make this example easier to follow. The script as published uses the setBackgroundRGB call, rather than setBackgroundColor, which you see above. The getColor_ function was changed as follows:

if (iteration == max_iteration) {
   return '#000000';
} else {
   var c = 255 - (iteration * 5);
   c = Math.min(255, Math.max(0, c));
   var hex = Number(c).toString(16);
   while (hex.length < 2)
     hex = '0' + hex;

   return ('#' + hex + '3280');
}
ReyAnthonyRenacia
2017-05-22