Как добавить 2D-массив несколько раз в конце существующего 2D-массива, используя цикл for? - PullRequest
0 голосов
/ 25 апреля 2018

Начальная точка (граничные условия):

  • Существует множество повторяющихся событий каждую неделю (раздел еженедельных событий). row 9:11).
  • Мои коллеги могут установить начальную дату A6 и сколько недель они хотели бы добавить A5. Начальная ситуация:

Цель:
Запуск сценария должен добавить A5 количество недель, начиная с даты A6, к разделу «предстоящие события» (row 22 and following) с правильной датой. Вот как это будет выглядеть после успешного запуска скрипта:

Что работает до сих пор:
Сценарий может добавлять повторяющиеся события на одну неделю в правильном порядке в раздел предстоящих событий. Это работает также, если начальная дата находится в середине недели. (Не показано здесь, поскольку это, вероятно, не имеет значения.)

Мой код:

function recurringWeeks() {
  var ss = SpreadsheetApp.getActiveSheet(); // selects the active spreadsheet
  var repeatingWeeks = ss.getRange(5,1).getValue(); // gets how many weeks it should repeat
  var regWeek = ss.getRange(9, 2, 3, 7).getValues(); // gets the regular week data
  var regWeekRepeated = ss.getRange(9, 2, repeatingWeeks*3, 7); // create an array to store the events for all weeks

  // fill regWeekRepeated with regWeek
  for (var j = 0; j < repeatingWeeks; j++){
    for (var i = 0; i < 3; i++){
      regWeekRepeated[i+j*3] = regWeek[i];
  }
  }  

  // Repeat week for "A5" times and add to start/end date a week
  for (var j = 0; j < repeatingWeeks; j++){
    for (var i = 0; i < 3; i++){
    regWeekRepeated[i+j*3][0] = new Date(regWeek[i][0].getTime() + j*7*3600000*24); // <-This line leads to an error message.
    }
  }

  ss.getRange(ss.getLastRow()+1,2,repeatingWeeks*3,7).setValues(regWeekRepeated); // copies weekly events after the last row
}

Редактирование [i + j * 6] в [i + j * 3] в Repeat week for "A5" times and add to start/end date a week

Подход:
Поскольку я решил, как добавить одну неделю повторяющихся событий с правильной датой и правильным порядком, я использую это как свою «точку атаки». Я почти уверен, что for-loop выполняет свою работу, и в настоящее время это мой любимый инструмент.

  • создать массив (regWeek), заполненный повторяющимся событием для одного неделя с правильным порядком и датами. DONE

  • создайте массив (regWeekRepeated) и заполните его A5 числом обычные недели (regWeek), начиная с даты A6. ОШИБКА 1 : Объект не позволяет добавлять или изменять свойства.

  • внести изменения в заполненный массив regWeekRepeated. ОШИБКА 2 : TypeError: Невозможно установить для свойства "0.0" неопределенного значения "(класс) @ 3d8e4650"
  • Скопируйте значения в раздел «предстоящие события». DONE

Лучший хит, который я нашел в результатах поиска: создание двухмерных массивов Однако для этого используется .push, и, насколько я понимаю, это означает, что элемент (может быть строкой) помещается в конец массива. Я тоже пытался использовать push, но пока не увенчался успехом.

Вопросы :

  • ОШИБКА 1: Почему невозможно присвоить значение элемента из массива regWeek массиву regWeekRepeated? решаемые
  • ОШИБКА 2: Эта проблема со свойством связана с ОШИБКОЙ 1 или чем-то другим? Я пытался решить обе ошибки в отдельности. решаемые

  • Какой подход имеет больше смысла (логически или с точки зрения производительности) в этом контексте: помещать отдельные строки в конец существующего массива или использовать целую неделю в качестве строительных блоков массива?

Демонстрационная версия электронной таблицы

Обновление V01 :
Изменения: regWeekRepeated теперь является массивом.
Я изменил for loop из-за полученных отзывов.

  // fill regWeekRepeated with regWeek
  var regWeekRepeated = [];
  for (var j = 0; j < repeatingWeeks; j++){
    for (var i = 0; i < 3; i++){
      regWeekRepeated.push(regWeek[i]);
    }
  }
  Logger.log(regWeekRepeated)

Обновление V02 :

  // Repeat week for "A5" times and add to start/end date a week
  for (var j = 0; j < repeatingWeeks; j++){
    for (var i = 0; i < 3; i++){
    regWeekRepeated[i+j*3][0] = new Date(regWeek[i][0].getTime() + j*7*3600000*24); //adds a week to the dates for each cycle
    //Logger.log(regWeekRepeated[i]); // log is as expected and desired
    }
    Logger.log(regWeekRepeated); // second part of log not as expected.
  }
  //Logger.log(regWeekRepeated);
  ss.getRange(ss.getLastRow()+1,2,repeatingWeeks*3,7).setValues(regWeekRepeated); // copies weekly events after the last row

Здесь вывод журнала размещен во «внешнем» for loop. 1 представляет первый цикл, 2 второй цикл Похоже, вторая for loop перезаписывает элементы от 0 до 2.

А вот вывод в гугл листах

Обновление V03 :
Это гарантирует, что изменения не влияют на копию.

  // fill regWeekRepeated with regWeek
  for (var j = 0; j < repeatingWeeks; j++){
    for (var i = 0; i < 3; i++){
      regWeekRepeated[i+j*3] = regWeek[i].slice(); // shallow copy of an array
  }
  }

Ответы [ 2 ]

0 голосов
/ 25 апреля 2018

Создание сценариев для электронных таблиц может быть затруднено, потому что электронная таблица и жаргон / лексика JavaScript используют одни и те же термины по-разному. Возможно, это то, что здесь происходит.

  • ОШИБКА 1: Почему невозможно присвоить значение элемента из массива regWeek массиву regWeekRepeated?

regWeekRepeated - это объект Range, а не массив JavaScript

  • ОШИБКА 2: Эта проблема со свойством связана с ОШИБКОЙ 1 или чем-то другим? Я пытался решить обе ошибки по отдельности.

Да, это связано. Смотрите предыдущий ответ.

  • Какой подход имеет больше смысла (логически или с точки зрения производительности) в этом контексте: выдвигать отдельные строки в конец существующего массива или использовать целую неделю в качестве строительных блоков массива?

Мы могли бы сказать, что вызовы классов и методов Google Apps Scripts "дороги", поэтому мы должны постараться свести к минимуму количество обращений к таким элементам. Один из способов сделать это - передать значения диапазона в массив JavaScript, а затем внести все изменения непосредственно в него, и мы закончим передачу полученных значений в соответствующий диапазон.

Чтобы передать значения диапазона в 2D-массив JavaScript, используйте range.getValues ​​(), а чтобы передать значения 2D-массива JavaScript в диапазон, используйте range.setValues ​​().

0 голосов
/ 25 апреля 2018

regWeekRepeated не является массивом.getRange() не возвращает массив.

Попробуйте изменить значение с

var regWeekRepeated = ss.getRange(9, 2, repeatingWeeks*3, 7); // create an array to store the events for all weeks

на

var regWeekRepeated = ss.getRange(9, 2, repeatingWeeks*3, 7).getValues(); // create an array to store the events for all weeks

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

var regWeekRepeated =[];
...