62

我在 Google 表格(activerange)中选择了一系列单元格。我想遍历该范围内的每个单元格,并在末尾添加一个字符串。字符串始终相同,并且可以硬编码到函数中。

这似乎是一件非常简单的事情,但我已经把代码弄乱了一个小时,没有任何有用的事情发生,而且文档真的没有帮助。

这就是我现在所拥有的。我不编写 JS 代码(我确实知道 VBA,因为这会有所帮助..)。

function appendString() {
  var range = SpreadsheetApp.getActiveSheet().getActiveRange();
  for (var i = 0; i < range.length; i++) {
    var currentValue = range[i].getValue();
    var withString = currentValue + " string";
    range[i].setValue(withString);
  }
}
4

8 回答 8

113

你可以尝试这样的事情:

//
// helper `forEachRangeCell` function
//

function forEachRangeCell(range, f) {
  const numRows = range.getNumRows();
  const numCols = range.getNumColumns();

  for (let i = 1; i <= numCols; i++) {
    for (let j = 1; j <= numRows; j++) {
      const cell = range.getCell(j, i)

      f(cell)
    }
  }
}

//
// Usage
//

const range = SpreadsheetApp.getActiveSheet().getActiveRange();

forEachRangeCell(range, (cell) => {
  cell.setValue(`${cell.getValue()} string`)
})
于 2012-11-28T12:53:32.533 回答
22

或者使用setValues()同时写入所有值。似乎也执行得更快。

var range = SpreadsheetApp.getActiveSheet().getActiveRange();
var numRows = range.getNumRows();
var numCols = range.getNumColumns();
var writeValues = []
for (var i = 1; i <= numRows; i++) {
  var row = []
  for (var j = 1; j <= numCols; j++) {
    var currentValue = range.getCell(i,j).getValue();
    var withString = currentValue + " string";
    row.push(withString)
  }
  writeValues.push(row)
}
range.setValues(writeValues)
于 2015-04-19T14:07:18.530 回答
14

2020 年 3 月编辑:您现在可以使用现代 ECMAScript。如果启用 V8 运行时,则可以:

function appendString() {
  const range = SpreadsheetApp.getActiveSheet().getActiveRange();
  const values = range.getValues();
  const modified = values.map(row => row.map(currentValue => currentValue + " string"));
  range.setValues(modified);
}

如果您必须使用较旧的 Javascript 版本,您可以:

function appendString() {
    var range = SpreadsheetApp.getActiveSheet().getActiveRange();
    var values = range.getValues();

    values.forEach(function(row, rowId) {
        row.forEach(function(col, colId) {
            values[rowId][colId] += " string";
        });
    });

    range.setValues(values);
}

请注意,rowId并且colId是从零开始的。在接受的答案中,索引是基于 1 的。或者您map不使用箭头运算符:

function appendString() {
  var range = SpreadsheetApp.getActiveSheet().getActiveRange();
  var values = range.getValues();

  var modified = values.map(function (row) {
    return row.map(function (col) { 
      return col + " string"; 
    }); 
  })

  range.setValues(modified);
}
于 2019-01-16T19:09:29.420 回答
7

这是Voy 帖子的更新,使用range.getValues()获取所有值并省略临时数组。应该更快,因为range.getCell().getValue()在二维循环中省略了。请注意,索引从此0片段中开始。我也觉得这更具可读性。

  var cells = range.getValues();
  var numRows = range.getNumRows();
  var numCols = range.getNumColumns();
  for (var i = 0; i < numRows; i++) {
    for (var j = 0; j < numCols; j++) {
      cells[i][j] += " string";
    }
  }

  range.setValues(cells);
于 2018-08-17T19:59:11.040 回答
3

这是一个非常通用的函数,它迭代一个范围的值。它也可以用来reduce在它上面做一个功能(这在你的情况下很有用)。如果您只想找到元素的第一个,它也可以跳出循环。

它可以很容易地更改为接受实际的 Range 实例而不是值数组。

function range_reduce(rangeValues,fn,collection) {
  collection = collection || [];
  var debug_rr = "<<";
  for(var rowIndex = 0, row=undefined; rowIndex<rangeValues.length && (row = rangeValues[rowIndex]); rowIndex++) { 
    for(var colIndex = 0, value=undefined; colIndex<row.length && (value = row[colIndex]); colIndex++) {
      try {
        collection = fn(collection, value, rowIndex, colIndex);
      } catch (e) {
        if(! e instanceof BreakException) {
          throw e;
        } else {
          return collection;
        }
      }
    }
  }
  return collection;
}

// this is a created, arbitrary function to serve as a way
// to break out of the reduce function. Your callback would
// `throw new BreakException()` and `rang_reduce` would stop
// there and not continue iterating over "rangeValues".
function BreakException();

在你的情况下:

var range = SpreadsheetApp.getActiveSheet().getActiveRange()
var writeValues = range_reduce(range.getValues(), function(collection, value, row, col) {
    collection[row] || collection.push([]);
    collection[row].push(value + " string");
});
range.setValues(writeValues)
于 2015-11-04T02:56:27.293 回答
1


您可以使用查找和替换轻松完成此操作。

  • 选择您的范围

  • 寻找:

    ^(.*)$
    
  • 代替:

    $1AppendString
    
  • 标记使用正则表达式

  • 点击全部替换

我看不出在这里使用脚本有什么好处,但是,如果必须,您也可以通过工作表 API发出Find Replace请求。

于 2019-01-16T15:59:19.367 回答
1

Google 表格使用多维数组,因此为了让您的生活更轻松,您可以像这样展平数组:

range.getValues().flat().forEach(function(item, i){
    var currentValue = item[i].getValue();
    var withString = currentValue + " string";
    item[i].setValue(withString);
});

于 2021-01-08T17:27:21.790 回答
0

我就是这样做的。它有点长,但我认为它非常实用且可重复使用。绝对实用。

这使用 V8 引擎和 TypeScript

/*
    Transforms the original "Array of Arrays"—
    [
        [a, b, c, d, e],
        [a, b, c, d, e],
        [...],
        ...,
    ]
  
    into an "Array of Objects".
    [
        {timestamp: a, email: b, response_1: c, response_2: d, response_3: e},
        {timestamp: a, email: b, response_1: c, response_2: d, response_3: e},
        {...},
        ...,
    ]
*/
var original_values = SpreadsheetApp.getActiveSheet()
  .getRange("A:E")
  .getValues()
  .map(
    ([
      a, b, c, d, e,
   // f, g, h, i, j,
   // k, l, m, n, o,
   // p, q, r, s, t,
   // u, v, w, x, y,
   // z, aa, ab, ac, ad,
   // etc...
    ]) => {
      return Object.create({
        timestamp: a,
        email: b,
        response_1: c,
        response_2: d,
        response_3: e,
      });
    }
  );

/*
    Appends the string to some part of the Objects in our Array.
    Since the Objects match the table structure (hopefully) we can be
    pretty specific.
    
    I tried to mock how a Google Form might collect responses.
*/
var appended_string = original_values.map(
  (arg: { timestamp; email; response_1; response_2; response_3 }) => {
    switch (typeof arg.response_1) {
      case "string":
        return Object.assign(arg, {
          response_1: (arg.response_1 += " string"),
        });

      default:
        return arg;
    }
  }
);

/*
    Need to reshape the "Array of Objects" back into an "Array of Arrays".
    Pretty simple compared to the original.
*/
var values_to_set = appended_string.map(
  (arg: { timestamp; email; response_1; response_2; response_3 }) => {
    return [
      arg.timestamp,
      arg.email,
      arg.response_1,
      arg.response_2,
      arg.response_3,
    ];
  }
);

/*
    Here we'll take our finalized "values_to_set Array of Arrays" and
    use it as the input for ".setValues()".

    All Google Sheets data starts and ends as an "Array of Arrays" but...
    It is significantly easier to work with as an "Array of Objects".

    Rhetorical Question: Who wants to keep track of indexes?
*/
SpreadsheetApp.getActiveSheet().getRange("A:E").setValues(values_to_set);
于 2021-04-05T16:41:57.227 回答