【问题标题】:Getting a range from a range in Google Apps scripting从 Google Apps 脚本中的范围获取范围
【发布时间】:2018-07-18 01:31:35
【问题描述】:

有没有办法从范围中获取子范围?

即。

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

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

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

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

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

它运行良好,除了运行速度非常慢,我正在尝试找出一种方法让它更快。我猜它慢的原因之一是因为我在循环中使用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);
}

【问题讨论】:

    标签: google-apps-script google-sheets


    【解决方案1】:

    Range#getCell 是从现有Range 中引用Range 的方式,因此您已经在做您要求做的事情。正如您所注意到的,使用Range#setDataValidations 优于逐个单元格设置,因为它是一种批处理方法。鉴于您使用requireValueInRange 验证规则,因此无法避免获得额外的Ranges。

    但是,对于具有明确定义关系的特定用例,通过使用RangeLists,可以更有效地获取它们。 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
    }
    

    参考文献

    【讨论】:

    • 使用RangeLists 成功了……从 5 分钟(约 300 行)到 1 分钟(约 5000 行)。谢谢!
    【解决方案2】:

    下面的示例允许获取由所有行和仅一些列组成的 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)
    }
    

    【讨论】:

      【解决方案3】:

      我创建了一个简单的函数,根据数据的大小用数据填充给定的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)
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-28
        • 2020-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多