Итерация по диапазону, добавление строки к каждому
У меня есть ряд ячеек, выбранных в Google Sheets (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);
}
}
Ответы
Ответ 1
Вы можете попробовать что-то вроде этого:
function appendString() {
var range = SpreadsheetApp.getActiveSheet().getActiveRange();
var numRows = range.getNumRows();
var numCols = range.getNumColumns();
for (var i = 1; i <= numRows; i++) {
for (var j = 1; j <= numCols; j++) {
var currentValue = range.getCell(i,j).getValue();
var withString = currentValue + " string";
range.getCell(i,j).setValue(withString);
}
}
}
Ответ 2
Или используйте 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)
Ответ 3
здесь обновление до сообщения 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);
Ответ 4
Вот очень универсальная функция, которая выполняет итерацию над значениями диапазона. Его также можно использовать для выполнения функции 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)
Ответ 5
Я предпочитаю метод Javascript 1.6 forEach
сравнению со старой школой for
циклов. Вы можете:
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 начинаются с нуля. И не на основе одного, как решения старой школы. Javascript 1.6 также предлагает 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);
}
С помощью функций со стрелками код улучшится, но они пока не поддерживаются в google-apps-script.
Ответ 6
Вместо старой школы for
циклов, вы можете использовать метод Javascript 1.6 forEach
.
function appendString() {
var range = SpreadsheetApp.getActiveSheet().getActiveRange();
var values = range.getValues();
var modifiedValues = [];
values.forEach(function (row) {
var modifiedRow = [];
row.forEach(function (value) {
var modifiedValue = value + " string";
modifiedRow.push(modifiedValue);
});
modifiedValues.push(modifiedRow);
});
range.setValues(modifiedValues);
}
Lambas будет лучше, но пока не поддерживается.
Это не будет работать:
function doesNotWork() {
var range = SpreadsheetApp.getActiveSheet().getActiveRange();
var values = range.getValues();
values.forEach(function(row) {
row.forEach(function(value) {
value += value + " string";
});
});
range.setValues(values);
}
Ответ 7
google-sheets
Вы можете легко сделать это с помощью Find and Replace.
Я не вижу здесь никакого преимущества в использовании скрипта, но, если необходимо, вы также можете выполнить запрос Find Replace через API листов.