Как писать скрипты, макросы и код в Google Scripts — часть 2

Доброго времени суток, дорогие читатели!

Продолжаем тему скриптов в гугле. В прошлой статье я описывал самые основы написания кода, сегодня же я бы хотел подробнее осветить такие штуки, как:

  • Методы и свойства объектов;
  • Условия и циклы.

script

Увы, пока еще достаточно много теории и мало практики, но без этого, опять же, увы, никуда.
Давайте приступим.


Методы и свойства объектов Google Scripts

Для тех, кто запамятовал, на данный момент наш код выглядит следующим образом:

function myfunction(){
    var sheet = SpreadsheetApp.getActiveSheet(); // Ссылаемся на текущий лист таблицы в соответствии с иерархией. В переменной sheet будет ссылка на наш лист
    /*-------------
    --Комментарий--
    ---------------*/
    var dataArray = sheet.getRange("A1:D3").getValues(); // Получаем значения ячеек A1:D3 в переменную dataArray
    var sum1 = dataArray[0][0] + dataArray[0][1] + dataArray[0][2] + dataArray[0][3];
    var sum2 = dataArray[1][0] + dataArray[1][1] + dataArray[1][2] + dataArray[1][3];
    var sum3 = dataArray[2][0] + dataArray[2][1] + dataArray[2][2] + dataArray[2][3];
    var avg1 = sum1/4;
    var avg2 = sum2/4;
    var avg3 = sum3/4;
    var array1 = [1, 2, 3, 4, 5];
    var array2 = ["1", "2", "3", "4", "5"];
    var array2d = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
    ];
    sheet.getRange("E1:F3").setValues([
    [sum1, avg1],
    [sum2, avg2],
    [sum3, avg3]
    ]);
};

Как вы могли заметить, у нас есть конструкции вида SpreadsheetApp.getActiveSheet() или sheet.getRange().getValues , которые многим кажутся очень непонятными (да, это нормально).

Разберем обе конструкции подробнее.

У нас есть объект SpreadsheetApp - он представляет собой возможность работы с таблицами в целом и является родительским (головным, основным, классом верхнего уровня, называйте как хотите) для таблиц. В общем, если вы хотите работать с таблицами гугла, то вам нужен этот объект.

Любой объект у гугла имеет определенный синтаксис (правила написания) вида <название объекта>.<метод/свойство объекта>, где.

  • Метод - это функция, которая принадлежит данному объекту (например объект - человек, методы: ходить, говорить, думать, читать и тп. В общем, какие-то действия).
  • Свойство - это характеристики (переменные) данного объекта (например объект - человек, свойства: имя, фамилия, дата рождения и тп).

При этом гугл не стал заморачиваться со свойствами и описал только методы (кроме некоторых объектов), чем сильно упростил работу нам :)

Полный список для каждого объекта можно найти (с примерами) на странице оф. документации (увы, она на английском).

Итак, возвращаясь к нашим примерам. У нас есть объект SpreadsheetApp для таблиц. Но мы же хотим работать не со всеми файлами таблиц гугла, а только с одним определенным (обычно, с тем, что у нас сейчас открыт). Как гугл поймет с каким именно файлом мы хотим работать? Нужно указать его идентификатор (у любого файла гугла есть идентификатор).

Как его узнать? Ну.. мы конечно можем узнать его каким-то способом и сообщить гуглу, но если глянуть в методы SpreadsheetApp, то у него есть один замечательный метод под названием getActiveSheet(). Он, грубо говоря, говорит гуглу: "Эй, чувак, я хочу узнать ссылку на текущую таблицу". И гугл дает нам идентификатор, поэтому важно записать его в какую-нибудь переменную, чтобы дальше не вызывать снова этот метод, а использовать уже готовую ссылку (как с ярлыками для папок в винде).

Так как метод - это функция, то любой метод оканчивается на круглые скобочки (). Эти скобочки как раз и указывают, что нам нужен метод, а не свойство. В таких скобочках для некоторых функций можно передавать значения (аргументы) для дальнейшей работы метода.  Например, мы могли бы получить ссылку на текущую таблицу через метод openByUrl(<адрес текущего файла>), но это не очень удобно :)

Что касается второй конструкции (sheet.getRange().getValues), то здесь тоже самое, но мы вызываем метод getValues для объекта Range, который в свою очередь получаем, обращаясь к методу getRange объекта Sheet, на который ведет ссылка sheet (да, это может быть сложновато для восприятия). Напишем конструкцию иначе:

var dataRange = sheet.getRange("A1:D3");
var dataArray = dataRange.getValues();

Если вернуться чуть раньше, то целиком мы получаем значения диапазона с помощью трех переменных:

var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange("A1:D3");
var dataArray = dataRange.getValues();

Но синтаксис работает таким образом, что вызывая метод верхнего объекта, вы получается объект уровнем ниже, для которого можете сразу вызвать метод его уровня, который вернет объект уровнем еще ниже, для которого... и так до самого нижнего уровня. Таким образом, например, мы можем обойтись вообще одной переменной вместо трех, если переиначим следующим образом:

var dataArray = SpreadsheetApp.getActiveSheet().getRange("A1:D3").getValues();

Здесь мы обратились к родительскому классу SpreadsheetApp, потом мы обратились к классу ниже Sheet, затем к классу еще ниже Range и для этого класса уже вызвали метод getValues().

Поначалу вам может быть сложновато сразу вызывать методы подклассов для упрощения некоторого кода, чтобы не плодить переменные. Поэтому можно использовать маленькую хитрость: сначала расписываете подробно, потом просто ужимаете, копируя нужные части. Как вы могли заметить с примером из трех переменных, я просто взял для последней переменной первый объект и присвоил ей все методы из правых частей:

Ужимаем код Google Scripts

С методами более менее разобрались, теперь займемся условиями и циклами.

к содержанию ↑

Циклы и условия Google Scripts

Вот у нас есть такие строки кода:

var sum1 = dataArray[0][0] + dataArray[0][1] + dataArray[0][2] + dataArray[0][3];
var sum2 = dataArray[1][0] + dataArray[1][1] + dataArray[1][2] + dataArray[1][3];
var sum3 = dataArray[2][0] + dataArray[2][1] + dataArray[2][2] + dataArray[2][3];

Код вроде бы удобен, но что делать, если, например, у нас увеличится кол-во рядов или строк? Переписывать каждый раз заново код? Не очень удобно, не так ли? :)

Здесь-то нам и пригодятся циклы. Если кратно, то цикл - это повторение какой-то операции до тех пор, пока условия цикла не будут выполнены. Основных вариантов цикла существует целых два - for и while. Их различие в том, что цикл for выполняется до тех пор, пока переменная цикла не достигнет определенного значения, а цикл while будет выполняться до тех пор, пока не будет выполнено определенное действие. При этом с циклами стоит быть несколько осторожными, т.к. очень легко создать бесконечный цикл (который будет выполняться пока ему не надоест или пока не сработает тайм-аут).

Рассмотрим пару примеров:

for (i=0; i < 100; i++){
    sum += i;
}

Данные строчки означают следующее:

У нас есть переменная цикла i (т.н. счетчик), которая каждый шаг цикла (итерацию) увеличивается на 1 (i++) и цикл будет длиться до тех пор, пока i не станет больше или равно 100. При этом каждую итерацию у нас в переменную sum будет прибавляться значение i (т.е. после такого цикла sum будет равно 0+1+2+3+4+...+99 = 4950).

Аналогичный примеру выше цикл while:

while (i < 100)
    sum += i;
    i++;
}

Дословно означает "Пока i меньше 100, делать следующее: прибавить к сумме значение i, затем увеличить i на 1".

С условиями все еще проще, конструкция условия выглядит таким образом:

if (условие) {
    действие
} else if (условие 2) {
    другое действие
}

Например, условие - если у вас 5 яблок, то увеличить их вдвое (вот бы так с деньгами, да?), иначе уменьшить их кол-во на 3:

if (apple == 5) {
    apple += apple;
} else {
    apple -= 3;
}

Итак, как с помощью этого нам упростить свой код?

Если приглядеться, то у нас довольно много повторяющихся строк (которые немного отличаются). У нас сейчас, по сути, для каждой строки по две переменные (sum и avg), учитывая, что строк три, получаем 6 переменных. Однако как мы можем обойтись всего двумя? Да очень просто, достаточно для каждой строки подсчитывать сумму и среднее значение, затем печатать его в соотв. ячейке и переходить к следующей строке.

Таким образом, мы обойдемся всего двумя переменными и при этом нам вообще неважно сколько строк использовать. Если рассматривать этот вопрос более детально, то что нам нужно сделать? Мы для каждой итерации (1 итерация = 1 строка) должны подсчитать сумму и среднее значение ячеек  этой строки. Однако, если мы захотим использовать больше или меньше ячеек, чем сейчас, то как нам это дело унифицировать? Тут нужен второй цикл, который будет просматривать каждую ячейку данной строки.

Теперь другой вопрос - как мы будем менять наш диапазон (строк и колонок)? Ну... тут магии нет, давайте просто создадим две переменные, которые будут отвечать за ширину и высоту диапазона (две переменные поменять всяко проще, чем кучу строк):

var rows = 3;
var cols = 4;

Т.е. у нас на данный момент три строчки (rows) по четыре значения в каждой (cols).

Прежде, чем создавать циклы, давайте несколько унифицируем эту строчку:

var dataArray = sheet.getRange("A1:D3").getValues();

Т.к. диапазон будет зависеть только от переменных rows и cols, то от явного указания области надо уходить. Ввиду того, что A1:D3 - это не очень удобное написание для нас, следует поискать более подходящий. Смотрим оф документацию и видим, ага, есть прямо то, что нам нужно:

Будем использовать метод getRange с явным указанием строк и колонок:

var dataArray = sheet.getRange(1, 1, rows, cols).getValues(); // getRange (ряд, колонка, кол-во рядов, кол-во колонок) 

Ну а дальше добавляем циклы:

for (var i = 0; i < rows; i++){ // для каждой строки:
    var sum = 0; // обнуляем переменную
    var avg = 0; // обнуляем переменную
    for (var j = 0; j < cols; j++){ // Для каждой ячейки в этой строке
       sum += dataArray[i][j]; // добавить значение ячейки в сумму
    } // перейти к следующей ячейке в строке
    avg = sum/cols; // посчитать среднее
    sheet.getRange(i+1, cols+1, 1, 2).setValues([ [sum, avg] ]); // записать значения
} // перейти к следующей строке

При этом, следует заметить, что мы используем другой формат записи getRange при записывании значений суммы и среднего. Т.к. у нас ячейка, в которую записывать, зависит от наших переменных rows, cols (если строк будет, например, 7, то записывать сумму и среднее следует в 8 и 9 строку).

Также обратите внимание, что номер ряда обозначается переменной i+1, а не i, т.к. нумерация рядов идет от единицы, а итерация идет с нуля (т.к. нумерация элементов массивов также идет с нуля).

Собираем наш код обратно и получаем такую конструкцию:

function myfunction(){
    var sheet = SpreadsheetApp.getActiveSheet(); // Ссылаемся на текущий лист таблицы в соответствии с иерархией. В переменной sheet будет ссылка на наш лист
    /*-------------
    --Комментарий--
    ---------------*/
    var rows = 3; // кол-во строк
    var cols = 4; // кол-во ячеек в строке
    var dataArray = sheet.getRange(1, 1, rows, cols).getValues(); // getRange (ряд, колонка, кол-во рядов, кол-во колонок)
    for (var i = 0; i < rows; i++){ // для каждой строки:
        var sum = 0; // обнуляем переменную
        var avg = 0; // обнуляем переменную
        for (var j = 0; j < cols; j++){ // Для каждой ячейки в этой строке
            sum += dataArray[i][j]; // добавить значение ячейки в сумму
        } // перейти к следующей ячейке в строке
        avg = sum/cols; // посчитать среднее
        sheet.getRange(i+1, cols+1, 1, 2).setValues([ [sum, avg] ]); // записать значения
    } // перейти к следующей строке
};

Теперь попробуйте увеличить кол-во строк и рядов, не забыв при этом поменять значения переменных rows и cols и запустите скрипт снова ;)

Стало куда удобней, но.. может можно еще уменьшить наши телодвижения? Программисты - это народ такой, ленивый, чем меньше надо менять значений, тем лучше :)

Теперь вместо того, чтобы добавлять каждый раз новые переменные для строк и ячеек, нам достаточно просто вручную указать размер области, откуда брать значения. Но! Можно и это не указывать, пусть система сама определяет эту область. Она же может видеть, где начинаются пустые ячейки? Ну ведь может, да? Как нам это узнать?

Давайте опять обратимся к документации (я вообще рекомендую почаще к ней обращаться, там очень много полезной информации) и поищем какой-нибудь метод для класса sheet (т.к. нам нужно узнать есть ли какой метод для выявления последнего непустого ряда/колонки на всем листе). Метод должен, по идее, начинаться со слов get (ведь нам надо что-то получить от него). И.. о, такой метод есть, даже два:

Методы sheet Google Scripts

Это методы getLastColumn() и getLastRow(). Они занимаются тем, что возвращают нам значение последнего непустого ряда или колонки. Теперь просто заменим строчки:

    var rows = 3; // кол-во строк
    var cols = 4; // кол-во ячеек в строке

На:

    var rows = sheet.getLastRow(); // кол-во строк
    var cols = sheet.getLastColumn(); // кол-во ячеек в строке

И попробуем изменить наш диапазон, добавив или удалив строки/колонки.

к содержанию ↑

Послесловие

Чтож, надеюсь кто-то до этого момента все таки дочитал :) Как и всегда, ждем Ваших вопросов, дополнений и всего такого прочего, что может появится в результате прочтения данной статьи.

Пожалуй, в следующей части я опишу как все тоже самое выглядит в скриптах VBA-экселя.

P.S. За существование оной статьи отдельное спасибо другу проекта и члену нашей команды под ником “barn4k“.
P.S 2: Прошлые части обитают здесь и здесь.

Sonikelf's Project's логотип Sonikelf's Project's логотип Космодамианская наб., 32-34 Россия, Москва (916) 174-8226
Sonikelf

Суровое начало года :)

Денис Борискин

ехуууууу Соник вернулся =)

Sonikelf

Ну еще не совсем :)

zxy

Найс! Спасибо за новую статью в цикле!

Sonikelf

Пожалуйста

наталья

Ничего не понятно. Лучше о понятном рассказывайте о том, что попроще.
Зайду через пару недель может что нужное появится.

Sonikelf

Попробуйте почитать прошлые статьи по этой теме :)
Ну или может Вам просто оно не нужно ;)

zxy

Тут уж кому как

Sonikelf

Это да :)

Дмитрий

Будем изучать дальше, спасибо!

Sonikelf

Пожалуйста

Clandir

тяжко, но будем осваивать дальше)

Sonikelf

Успехов :)

ddimae

Хорошая статья. Как человек, работающий с VBA, говорю огромное спасибо. Базы данных - это хорошо, но много компаний все еще бережет самое ценное в Excel, но плавно переводит его в Googl Tabs. Поэтому очень полезный материал

Николай

Помогите написать скрипт. Есть на первом листе таблица с данными: Имя, Мероприятие и участвовал там человек или нет. Нужно на втором листе вывести таблицу с именами и где не принимал участие этот человек. Как записать данные таблицы в массив двумерный? Как вывести массив? Можно ли вывести одной строчкой всю таблицу, без использования двойных массивов и перебором каждой ячейки?

barn4k

Добрый день! Извините за долгий ответ, может еще актуально.

Здесь достаточно формулы, нет смысла использовать скрипт. Например у вас на Листе1 в столбце А имена людей, в столбце В названия мероприятий, в столбце С - участвовал человек или нет (Да/Нет)
Тогда на Листе2 пишете такую формулу:
=FILTER('Лист1'!A2:B25; 'Лист1'!C2:C25 = "Нет")

Артур

Спасибо за цикл статей. Классно разжевано все! Пытался решить проблему обновления данных полученных через IMPORTXML()
С вашей помощью собрал костыль!

barn4k

Рады, что пригодилось!

Vladimir

Только недавно начал изучать программирование и Googlescripts в частности, ваша статья очень пригодилась в понимании концепции взаимодействия с объектами. Хотелось бы увидеть продолжение

Vladimir

Вопрос. Почему в последней строчке:

sheet.getRange(i+1,cols+1, 1, 2).setValues([[sum, avg]]);

подставляем не j, а вместо него cols. Или же не rows вместо i

Vladimir

Как тему для будущих статей могу предложить: применение googlescripts для googledrive, g-mail и прочих сервисов, а также построение CMS и CRM систем

Sonikelf

Как вариант, спасибо

Дмитрий

Серия статей хороша. Может кто помочь. Необходим скрипт интересный, простой но не могу дотукать. Есть 2 столбца с ценами, и есть н столбцов с чек боксами ( фалс / тру) . необходимо чтобы по событию редактирования цены, чек боксы слетали.

Артур

Чек боксы в гугл таблицах? Сбросьте пример таблицы

CherkVS

Большое спасибо за руководство. Я почти все понял, но у меня принципиальный вопрос, на который я не нашел ответ. Написанная функция может иметь параметры, и могу ли я созданную мной функцию вызвать в определенной ячейке (или в строке ячеек), а функция выполнила требуемые действия в ней и соседней строке. Спасибо.

Алексей

Спасибо за статью. Сможешь помочь с задумкой. Есть скрипт он работает если в активной ячейке из нужного столбца нажали на флажок=1, то на нужную почту ушло сообщение.
Хотелось бы в письмо добавить значения рядом с активной ячейкой или строку активной ячейки
function sheetTracker(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveCell();
var range = ss.getActiveRange();
var data = range.getValues();
// в следующей строке указывается емейл владельца -его изменения не отправляются почтой
if(range.getColumn() == 35 && Session.getActiveUser()!='[email protected]' &&
Number(ss.getActiveCell().getValue())==1){
MailApp.sendEmail('[email protected]', 'ЦПЖТ отчет',
'Добрый день! ЦПЖТ - ячейка изменена' + ss.getActiveCell().getValue().toString());
}
}

barnak

Добрый день!
вконце поменяйте на:
'Добрый день! ЦПЖТ - ячейка изменена' + ss.getActiveCell().getValue().toString()) + ss.getActiveCell().offset(0,1).getValue().toString());

где offset (0,1) - означает сместить ячейку на 0 рядов вниз и 1 колонку правее

PS Session.getActiveUser() - эта команда почти нигде не работает. Там очень жесткие ограничения с ее работой (как минимум домен G Suite нужен). В 99% она будет возвращать почту создателя скрипта

Алексей

Сапсибо, про offset совсем позабыл - помогло, работает как нужно теперь. Если можно еще вопрос хотел реализовать скрипт копирования строк которые удовлетворяют определенному условию условию, например значение ячейки = true или 1. Пока получилось просто копировать активный диапазон в новую книгу.
function copyRow()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source_sheet = ss.getSheetByName("апрель");
var target_sheet = ss.getSheetByName("май");
var source_range = source_sheet.getActiveRange();
var last_row = target_sheet.getLastRow();
target_sheet.insertRowAfter(last_row);
var target_range = target_sheet.getRange("A"+(last_row+1)+":AX"+(last_row+1));
source_range.copyTo(target_range);
}

есть предположение что вот так будет работать - но у меня выходит просто пустая строка
function copyRow()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source_sheet = ss.getSheetByName("апрель");
var target_sheet = ss.getSheetByName("май");
var source_range = source_sheet.getActiveRange();
var last_row = target_sheet.getLastRow();
target_sheet.insertRowAfter(last_row);
var target_range = target_sheet.getRange("A"+(last_row+1)+":AX"+(last_row+1));
var arrIds = source_sheet.getRange("AW11:AW1000").getValues()
for(var i = 0; i<arrIds.length; i++){
if(arrIds == 1){
source_range.copyTo(target_range);
}
}
}

Буду признателен за помощь

Борис

В итоге скрипт из примера не заработал, пока не указал явно на то, что переменные это числа. Возможно на момент написания у гугла был другой синтаксис. Но на 26.03.19 он просто пытался склеить строки как текстовые, пока я явно не добавил указание Number(dataArray[i][j]);

В итоге получилось :
function SMCYСLE(){
var sheet = SpreadsheetApp.getActiveSheet(); // Ссылаемся на текущий лист таблицы в соответствии с иерархией. В переменной sheet будет ссылка на наш лист
/*-------------
--Комментарий--
---------------*/
var rows = 3; // кол-во строк
var cols = 4; // кол-во ячеек в строке
var dataArray = sheet.getRange(1, 1, rows, cols).getValues(); // getRange (ряд, колонка, кол-во рядов, кол-во колонок)
for (var i = 0; i < rows; i++){ // для каждой строки:
var sum = 0; // обнуляем переменную
var avg = 0; // обнуляем переменную
for (var j = 0; j < cols; j++){ // Для каждой ячейки в этой строке
sum += Number(dataArray[i][j]); // добавить значение ячейки в сумму
} // перейти к следующей ячейке в строке
avg = sum/cols; // посчитать среднее
sheet.getRange(i+1, cols+1, 1, 2).setValues([ [sum, avg] ]); // записать значения
} // перейти к следующей строке
};

Борис

Если кто будет проверять скрипт, название функции меняйте на свое или на myfunction(). Возможен конфликт с системой.

Борис Остроушко

Усовершенствовал немного скрипт, поскольку, при больших объемах данных, намного лучше и быстрее, если информация обрабатываться на месте и только после этого отправляется на сервер одним запросом. В оригинальном скрипте количество запросов будет равно количеству строк обрабатываемого массива.

Также хочу выразить огромную благодарность авторам данного цикла статей, поскольку в основном благодаря им и разобрался как работать с массивами. Очень была больная тема для меня. Ребята - вы огромные молодцы!

function SumAvgMassCycle(){
var sheet = SpreadsheetApp.getActiveSheet(); // Ссылаемся на текущий лист таблицы в соответствии с иерархией. В переменной sheet будет ссылка на наш лист
/*-------------
--Комментарий--
---------------*/
var rows = sheet.getLastRow(); // кол-во строк
var cols = sheet.getLastColumn(); // кол-во ячеек в строке
Logger.log (rows +" "+ cols);

var dataArray = sheet.getRange(1, 1, rows, cols).getValues(); // getRange (ряд, колонка, кол-во рядов, кол-во колонок)
var resultArray = []; //создаем переменную (массив) для сбора результатов
for (var i = 0; i < rows; i++){ // для каждой строки:
var sum = 0; // обнуляем переменную
var avg = 0; // обнуляем переменную
for (var j = 0; j < cols; j++){ // Для каждой ячейки в этой строке
sum += Number(dataArray[i][j]); // добавить значение ячейки в сумму
} // перейти к следующей ячейке в строке
avg = sum/cols; // посчитать среднее
resultArray.push([sum, avg]); //собираем результаты вычислений в массив результатов
}
Logger.log (resultArray); //проверяем как массив выглядит в журнале
// перейти к следующей строке

sheet.getRange(1, cols+1, rows, 2).setValues( resultArray ); //одним запросом записываем результаты

};

barn4k

Видимо гугл немного поменял логику. Либо у вас в свойствах ячейки явно был задан тип "текстовый".
что касается скрипта, то массив лучше всего создавать такой командой:
var resultArray = new Array();

А так валидацию типа переменной лучше всегда делать, если вы хотите, чтобы у вас переменная воспринималась так, как вы подразумеваете, а не как компилятор гугла посчитает удобнее :)

Борис Остроушко

Спасибо за совет насчет создания массива. Очень ценно, особенно для новичков. Пометил себе.

апрапр

В кучу все смешал: и пытается объяснить синтаксис и философию JS, и методов гугловской реализации сценариев. В итоге ни то, ни то не получилось объяснить. В голове у автора выступает цирк шапито

Лёша

Добрый день! Спасибо за серию статей, для новичка очень много полезной инфы. Позвольте вопрос задать. Я бы хотел скриптом копировать строку(в другой лист) при проверке столбца на значение, а потом эту строку удалять. Собрал 2-а скрипта, на удаление строки по значению столбца и копирование активного диапазона.
Как мне объединить эти скрипты чтобы до удаления строка сначала копировалась а потом удалялась.
function readRows() {
var ss = SpreadsheetApp.getActiveSheet();
var rows = ss.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if (row[48] == true) {
ss.deleteRow((parseInt(i)+1) - rowsDeleted);
rowsDeleted++;
}
}
};

function copyRow(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source_sheet = ss.getSheetByName("апрель");
var target_sheet = ss.getSheetByName("май");
var source_range = source_sheet.getActiveRange();
var last_row = target_sheet.getLastRow();
target_sheet.insertRowAfter(last_row);
var target_range = target_sheet.getRange("A"+(last_row+1)+":AX"+(last_row+1));
source_range.copyTo(target_range);
}

Буду признателен за подсказки

Ivan

Всем привет! Спасибо за статью
Помогите решить задачу, пожалуйста!
В Google Docs Sheets: есть ячейка, в которой можно выбрать тип валюты RUR, USD, EUR,ILS
В других вбивается числовое значение, в большинстве своём в рублях.
Какой нужен скрипт, чтобы при выборе той или иной валюты, определённые ячейки переводились автоматически по курсу.
Выглядит таблица подобным образом:
RUR <1 <3 <5 <10 <15 <20 <25
1 350 350 350 350 500 600 700
2 210 240 250 300 400 450 530
В ячейке A1 можно выбирать валюту RUR или USD и так далее.
Каким скриптом можно данные в ячейках B2:H3 чтобы автоматически пересчитывал в выбранную валюту?
Заранее, спасибо огромное за помощь!

Артур

Для начала нужно определиться откуда вы будете получать эти самые курсы валют? На самом деле скрипты тут и не нужны. Все решается стандартными функциями и формулами. Логика примерно такая:
Сначала парсите курсы валют с какого либо сайта через importxml()
Потом уже через условия if делаете пересчет валют. Если в ячейке a1 стоит RUR берем курс такой-то, если USD то другой. и т.д.

Викки

Здраствуйте, можете подсказать, почему в результате выводятся 0, а не суммы?
function mySum(){

var ss= SpreadsheetApp.getActiveSpreadsheet();
var ss4=ss.getSheetByName("Ввод периода");
var col1= ss4.getRange(2,1).getValues();
var col2= ss4.getRange(2,2).getValues();
var sheet = ss.getSheetByName("Приходы");
var rows = sheet.getLastRow(); // кол-во строк
var cols = sheet.getLastColumn(); // кол-во ячеек в строке
var month = sheet.getRange(1, 3, 1, cols).getValues();//значения месяц

for (var k = 0; k < month.length; k++) {
var row1 = "";
for (var l = 0; l < month[k].length; l++) {
if (month[k][l] == col1) {
row1 = month[k][l];
Logger.log(row1);
Logger.log(l);
}
}
}
for (var m = 0; m < month.length; m++) {
var row2 = "";
for (var n = 0; n < month[m].length; n++) {
if (month[m][n] == col2) {
row2 = month[m][n];
Logger.log(row2);
Logger.log(n);
}
}
}
var dataArray = sheet.getRange(2, 3, rows, cols).getValues(); // getRange
for (var i = 0; i < rows; i++){ // для каждой строки:
var sum = 0; // обнуляем переменную
for (var j = l; j < n; j++){ // Для каждой ячейки в этой строке
sum += +dataArray[i][j]; // добавить значение ячейки в сумму
} // перейти к следующей ячейке в строке
sheet.getRange(i+2, 2,1, 1).setValues([ [sum] ]); // записать значения
} // перейти к следующей строке
Logger.log([sum]);
}

barn4k

Добрый день!

Подозреваю, проблема в этом цикле: for (var j = l; j < n; j++).
У вас переменная dataArray имеет границы (2, 3, rows, cols), но в цикле вы определяете начальное значение и условие выхода через переменные l и n.

Чтобы сказать более точно, нужен примерю