从Google Apps脚本中获取范围

时间:2018-07-18 01:31:36

标签: google-apps-script google-sheets

是否可以从某个范围中获取一个子范围?

即。

var ss = SpreadsheetApp.getActiveSpreadsheet();
var fullRange = ss.getRange("A:P");

我可以从fullRange得到一个范围吗?

上下文是,我正在使用数据验证根据范围动态设置数据验证下拉列表。

示例:我有两个单元格-第一个单元格是一个带有类别列表的下拉列表,第二个单元格是一个带有一个子类别列表的下拉列表,这些子类别取决于在第一个单元格中选择的类别。

实现这一目标的方式是基于类别选择的,我根据该类别选择用子类别列表填充了隐藏行。然后,我使用requireValueInRange设置该子类别单元格的数据验证。

它运行正常,但运行SUPER的速度较慢,但​​我正在尝试找出一种使速度更快的方法。我猜它变慢的原因之一是因为我在循环中使用getRange来获取正确的requireValueInRange。因此,我尝试提取一个子范围,而不是每次都重新查询范围。

function setDataValidations() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var categoryRange = ss.getRange("A:A");
  var subCatCells = ss.getRange("B:B");

  var subCatRules = subCatCells.getDataValidations();

  var rangeLength = categoryRange.getValues().length;

  for (var i = 1; i < rangeLength; i++ ){
    var catCell = categoryRange.getCell(i, 1);
    var subCatOptions = ss.getRange("'subcats'!A" + i + ":P" + i);
    var subCatRule = SpreadsheetApp.newDataValidation().requireValueInRange(subCatOptions, true).build();
  }
  catCells.setDataValidations(subCatRules);
}

3 个答案:

答案 0 :(得分:3)

Range#getCell是如何从现有Range中引用Range的方式,因此您已经在执行要求的操作。如您所述,使用Range#setDataValidations优于逐个单元设置,因为它是批处理方法。假设您使用requireValueInRange验证规则,则无法避免获取额外的Range

但是,对于存在明确定义关系的特定用例,可以通过使用RangeList来更有效地获取它们。 RangeList是批量获取的Range,通常用于对不相交范围进行同等对待的用途。

function setDVs() {
  const wb = SpreadsheetApp.getActive();
  const catSheetName = "the name of the sheet that has the dropdowns",
      sheet = wb.getSheetByName(catSheetName),
      maxDVs = sheet.getLastRow();

  // Create the A1-notation or R1C1-notation Arrays identifying the ranges we need.
  const subCatNotations = [];
  const subCatSheetName = "the name of the sheet that has the ranges with required values"
  for (var r = 1; r <= maxDVs; ++r)
    subCatNotations.push("A" + r + ":P" + r); // 1 row, cols A:P

  // Range#setDataValidations requires an Array of Array of DataValidations.
  // Thus, wrap the new rule in a new array if updating a single column.
  const new_dvs = wb.getSheetByName(subCatSheetName)
      .getRangeList(subCatNotations).getRanges()
      .map(function (subCatRange) {
        return [
          SpreadsheetApp.newDataValidation().requireValueInRange(subCatRange, true).build()
        ];
      });

  // Batch-apply the new rules to the `catSheetName` sheet.
  if (new_dvs.length && new_dvs[0].length)
    sheet.getRange(1, 1, new_dvs.length, new_dvs[0].length).setDataValidations(new_dvs); // col A
}

参考

答案 1 :(得分:0)

下面的示例允许获得由所有行和仅某些列组成的subRange。

function getRangeByCols( myRange,  fromCol,  toCol){
  firstRowIndex = myRange.getRow()
  firstColIndex = myRange.getColumn()
  rowsNumber = myRange.getHeight()
  colsNumber = myRange.getWidth()

  return myRange.getSheet().getRange(firstRowIndex,firstColIndex+fromCol-1,rowsNumber,toCol-fromCol+1)
}

答案 2 :(得分:0)

我创建了一个简单的函数,根据数据的大小用数据填充给定的 Range

/**
 * Fills a range with the data provided (2D Array)
 * regardless of the number of rows/columns in the 
 * data
 **/
function fillRange(range, data) {
  range.clear({contentsOnly: true}) // Optional

  const target = range.getSheet().getRange(
    range.getRow(), range.getColumn(), 
    data.length, data[0].length)
  target.setValues(data)
}