将公式设置为多个单元格脚本-必须有更有效的方法

时间:2020-08-27 16:40:18

标签: google-apps-script google-sheets google-sheets-formula

在Google表格中,我想将以下内容应用于A2,A14,A26和A28,并将另一个公式应用于B2,B14,B26和B28。现在,我只做以下4次。可以,但是效果不佳。我如何才能更有效地做到这一点?

function onEdit(e) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheets = ss.getSheets();
  sheets[7].setName('.NCF');
  
  var sheet = ss.getSheets()[5];
  var cell1a = sheet.getRange("A2");
    cell1a.setFormula("=iferror(IF(QUERY('.NCF'!A2, \"where A contains '1ST'\")<>\"\", 1, ),\"\")");
  var cell1b = sheet.getRange("A14");
    cell1a.setFormula("=iferror(IF(QUERY('.NCF'!A14, \"where A contains '1ST'\")<>\"\", 1, ),\"\")");
  var cell1c = sheet.getRange("A26");
    cell1c.setFormula("=iferror(IF(QUERY('.NCF'!A26, \"where A contains '1ST'\")<>\"\", 1, ),\"\")");
  var cell1d = sheet.getRange("A38");
    cell1d.setFormula("=iferror(IF(QUERY('.NCF'!A38, \"where A contains '1ST'\")<>\"\", 1, ),\"\")");
    
  var cell2a = sheet.getRange("B2");
    cell2a.setFormula("=iferror(if(A2=1,query('.NCF'!A:A,\"Select A where A contains '( G54.1P'\"),\"\"),\"\")");
  var cell2b = sheet.getRange("B14");
    cell2a.setFormula("=iferror(if(A14=2,query('.NCF'!A:A,\"Select A where A contains '( G54.1P'\"),\"\"),\"\")");
  var cell2c = sheet.getRange("B26");
    cell2a.setFormula("=iferror(if(A26=3,query('.NCF'!A:A,\"Select A where A contains '( G54.1P'\"),\"\"),\"\")");
  var cell2d = sheet.getRange("B38");
    cell2a.setFormula("=iferror(if(A38=4,query('.NCF'!A:A,\"Select A where A contains '( G54.1P'\"),\"\"),\"\")");
}

3 个答案:

答案 0 :(得分:2)

function onEdit(e) {
  const ss = e.source;
  const sheets = ss.getSheets();
  sheets[7].setName('.NCF');
  const sheet = sheets[5];

  let a1;
  ['A', 'B'].forEach(column =>
    [2, 14, 26, 38].forEach((row, i) =>
      sheet
        .getRange((a1 = column + row))
        .setFormula(
          column === 'A'
            ? `=IFERROR(IF(QUERY('.NCF'!${a1}, "WHERE A CONTAINS '1ST'")<>"",1,))`
            : `=IFERROR(IF(A${row}=${i +
                1},QUERY('.NCF'!A:A,"SELECT A WHERE A CONTAINS '( G54.1P'"),))`
        )
    )
  );
}

另请参阅ternary operator

答案 1 :(得分:1)

解决方案:

这是我的解决方案,基于与TheMaster答案相同的逻辑。

  function onEdit(e) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheets = ss.getSheets();
  sheets[7].setName('.NCF');
  const sheet = ss.getSheets()[5];
  const cells1 = ['A2','A14','A26','A38'];
  const cells2 = ['B2','B14','B26','B38'];
  cells1.forEach(c=>          
     sheet.getRange(c).setFormula(`iferror(IF(QUERY('.NCF'!${c}, \"where A contains '1ST'\")<>\"\", 1, ),\"\")`)
  )                                                
  cells2.forEach((c,i)=>          
     sheet.getRange(c).setFormula(`iferror(if(${cells1[i]}=${i+1},query('.NCF'!A:A,\"Select A where A contains '( G54.1P'\"),\"\"),\"\")`)
  )   
}

说明:

很显然,您要使用两个单元格序列和两个公式。这就是我使用cells1cells2表示要分别应用公式1和2的单元格集的原因。您要调用此表达式:每个单元格都sheet.getRange().setFormula,这就是为什么可以使用forEach函数的原因。最后,我使用template literalscells表的元素合并到字符串参数中。

我的解决方案与其他解决方案之间的主要区别在于,我的forEach语句彼此之间没有链接,并且我不使用if语句。

答案 2 :(得分:1)

或者,您可以使用setValues批量应用这些值,以获得更好的性能。如果在值前加上=,则与设置公式本质上相同,因此,只能使用该方法设置值的事实无关紧要。

function onEdit(e) {

  const ss = SpreadsheetApp.getActiveSpreadsheet();

  const sheets = ss.getSheets();

  sheets[7].setName('.NCF');

  const [, , , , , sheet] = ss.getSheets();

  const rng = sheet.getDataRange();
  const vals = rng.getValues();
  const formulas = rng.getFormulas();

  const mixed = formulas.map((r, ri) => r.map((c, ci) => c || vals[ri][ci]));

  const toFormula = [2, 14, 26, 38].map(r => r - 1);
  let formulaIdx = 1;

  const newVals = mixed.map((row, ri) => {
    if (!toFormula.includes(ri)) {
      return row;
    }
    row[0] = `=iferror(IF(QUERY('.NCF'!A${ri+1}, \"where A contains '1ST'\")<>\"\", 1, ),\"\")`;
    row[1] = `iferror(if(A${ri + 1}=${formulaIdx++},query('.NCF'!A:A,\"Select A where A contains '( G54.1P'\"),\"\"),\"\")`;
    return row;
  });

  rng.setValues(newVals);

  console.log(rng.getValues());
}

带有模拟的可运行代码段:

function Range(grid) {
  return {
    getFormulas() {
      return grid.map(row => row.map(({
        formula
      }) => formula));
    },
    setFormulas(formulas) {
      grid.forEach((r, ri) => r.forEach((c, ci) => {
        grid[ri][ci].formula = formulas[ri][ci];
      }));
      return this;
    },
    setValues(values) {
      grid.forEach((r, ri) => r.forEach((c, ci) => {
        grid[ri][ci].value = values[ri][ci];
      }));
      return this;
    },
    getValues() {
      return grid.map(row => row.map(({
        value
      }) => value));
    }
  };
}

function Sheet(spreadsheet) {

  /** @type {{ value }[][]} */
  const grid = [];

  let sheetName = "Sheet1";

  return {
    activate() {
      spreadsheet.setActiveSheet(this);
      return this;
    },
    insertColumns(columnIndex, numColumns) {
      grid.forEach(row => {
        const cols = new Array(numColumns).fill("").map(() => ({
          value: "",
          formula: ""
        }));
        row.splice(columnIndex, 0, ...cols);
      });
      return this;
    },
    insertRows(rowIndex, numRows) {
      const rows = new Array(numRows).fill("").map(() => [{
        value: "",
        formula: ""
      }]);
      grid.splice(rowIndex, 0, ...rows);
      return this;
    },
    getLastRow() {
      const {
        length
      } = grid;
      return length;
    },
    getLastColumn() {
      const lengths = grid.map(({
        length
      }) => length);
      return Math.max(...lengths);
    },
    getDataRange() {
      return Range(grid);
    },
    getSheetName() {
      return sheetName;
    },
    setName(name) {
      sheetName = name;
      return this;
    }
  };
}

function Spreadsheet() {

  const defaultSheet = Sheet(this);

  const sheets = [defaultSheet];

  let active = defaultSheet;

  return {
    getSheets() {
      return sheets;
    },
    getActiveSheet() {
      return active;
    },
    insertSheet(sheetIndex = 0) {
      const sheet = Sheet(this);
      sheets.splice(sheetIndex, 0, sheet);
      return sheet.activate();
    },
    setActiveSheet(sheet) {
      active = sheet;
      return sheet;
    }
  };
}

var SpreadsheetApp = {
  getActiveSpreadsheet() {
    return Spreadsheet();
  }
};

function onEdit(e) {

  const ss = SpreadsheetApp.getActiveSpreadsheet();

  //prepare mock//
  for (let i = 0; i < 8; i++) {
    const sheet = ss.insertSheet();
    sheet.insertRows(0, 38);
    sheet.insertColumns(0, 2);

    const rng = sheet.getDataRange();
    const formulas = rng.getFormulas();
    formulas[5][2] = "=true";
    rng.setFormulas(formulas);
  }
  //end mock preparation//

  const sheets = ss.getSheets();

  sheets[7].setName('.NCF');

  const [, , , , , sheet] = ss.getSheets();

  const rng = sheet.getDataRange();
  const vals = rng.getValues();
  const formulas = rng.getFormulas();

  const mixed = formulas.map((r, ri) => r.map((c, ci) => c || vals[ri][ci]));

  const toFormula = [2, 14, 26, 38].map(r => r - 1);
  let formulaIdx = 1;

  const newVals = mixed.map((row, ri) => {
    if (!toFormula.includes(ri)) {
      return row;
    }
    row[0] = `=iferror(IF(QUERY('.NCF'!A${ri+1}, \"where A contains '1ST'\")<>\"\", 1, ),\"\")`;
    row[1] = `iferror(if(A${ri + 1}=${formulaIdx++},query('.NCF'!A:A,\"Select A where A contains '( G54.1P'\"),\"\"),\"\")`;
    return row;
  });

  rng.setValues(newVals);

  console.log(rng.getValues());
}

onEdit();


注释

  1. 您必须enable V8运行时才能使用摘要。
  2. 请注意,如果数据范围内有公式,则需要分别获取它们(使用getFormulas)并与值混合使用(请参阅mixed变量的初始化方式)。