Подтвердить что ты не робот

Итерация по диапазону, добавление строки к каждому

У меня есть ряд ячеек, выбранных в 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);
  }
}
4b9b3361

Ответ 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


Вы можете легко сделать это с помощью Find and Replace.

  • Выберите свой диапазон

  • Найти:

    ^(.*)$
    
  • Заменить:

    $1AppendString
    
  • Пометить регулярные выражения

  • Нажмите Заменить все

Я не вижу здесь никакого преимущества в использовании скрипта, но, если необходимо, вы также можете выполнить запрос Find Replace через API листов.