【问题标题】:Incrementor not updating after iteration of loop循环迭代后增量器不更新
【发布时间】:2021-09-30 12:39:03
【问题描述】:

总的来说,我是 stackover 流程​​和编码的新手。我整理了一个脚本,该脚本从数组中提取信息,该数组从主表中提取信息。脚本从模板中提取要提取的工作表类型,并根据数组数据对其进行填充。它适用于第一行数据,但我的变量在增量命令后没有更新,因此它卡在第一个条目上。抱歉,如果我解释得不好。 功能: 1.根据Arraydata第4行拉取房型 2.根据数组数据的第4行重命名 3.从Array数据的第4行填写数据 4.递增row变量,这样可以在第5行再次运行脚本,直到没有更多的数组数据。

为了安全,我已经替换了实际的工作表 ID

function createautomation() {
do{
var roomlist = SpreadsheetApp.getActiveSheet().getRange("Room List!A1:G100").getValues();
var i = 4
var ss = SpreadsheetApp.getActiveSpreadsheet();
var commissioning_template = SpreadsheetApp.openById('ID')
var roomtype = roomlist[i][5]
var copyroom = (`Copy of ${roomtype}`)
var ss = SpreadsheetApp.getActiveSpreadsheet();
var first = ss.getSheetByName(copyroom);
var roomname = roomlist[i][1]
var tab = (`${roomname} - ${roomtype}`)
var second = ss.getSheetByName(tab)
var room1 = (`${tab}!B1`)
var roomnum = (`${tab}!B2`)
var floor = (`${tab}!D2`)
var address = (`${tab}!B3`)
var siteName = (`${tab}!D3`)
var siteCode = (`${tab}!E3`)
var sourcenum = roomlist[i][0]
var sourceflr = roomlist [i][4];
//Copy The spreadsheet
commissioning_template.getSheetByName(roomtype).copyTo(ss);
//Rename Sheet
ss.getSheetByName(copyroom).setName(tab);
//Set Room Name
ss.getRange(room1).setValue(roomname);
//Set Room Number
ss.getRange(roomnum).setValue(sourcenum);
//Set Floor
ss.getRange(floor).setValue(sourceflr);
//Set Address
ss.getRange(address).setValue(roomlist[1][2]);
//Set Site Name
ss.getRange(siteName).setValue(roomlist[0][2]);
//Set Site Code
ss.getRange(siteCode).setValue(roomlist[2][2])
//increment the value of i
i++;
console.log(i)}
while(roomname !="")
}

【问题讨论】:

  • 您需要将创建var 变量的代码移动到do 循环内。您正在递增i,但每次迭代都没有获取索引项。
  • 谢谢马克。因此,即使我将 do{ 放在脚本的最顶部,包括所有变量。它似乎仍然没有增加。我已经使用 do 循环更新了脚本以包含变量
  • 如果您可以将数据安排在连续的单元格中,那么编码会有很大的好处,因为这样您就可以使用 setValues() 而不是几个 setValue()s
  • 每次循环读取所有数据真的很慢。如果您还没有这样做,我强烈建议您重新考虑您的整个函数并花一些时间学习数组方法。
  • 谢谢库珀!我将 var i = 4 排除在循环之外,这解决了这个问题。我正在使用数组数据精确地做到这一点,并且只增加数据行,因为这些列是其他单元格的来源。

标签: javascript google-apps-script google-sheets


【解决方案1】:

Marc 和 Cooper 关于您的功能的评论实际上是正确的。鉴于这些 cmets,我试图改进您的脚本。这将提高性能,但考虑到您正在处理的数据,我不确定它是否会对性能产生太大影响,但最好执行以下操作,因为这种方法在大型数据集中肯定会更好。

这些都是你可以改进的,如果你有时间,请检查一下。

function createautomation() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();

  var roomlist = ss.getSheetByName("Room List") // get sheet separately from range
                   .getRange('A1:G100')         // you can also use A1:G if the column can grow past 100 and not sure until where           
                   .getValues()
                   .filter(row => row[1]);      // only include rows that have values on second column

  // pull all variables that are static in the loop
  var address = roomlist[1][2];
  var sitename = roomlist[0][2];
  var sitecode = roomlist[2][2];
  // separated tab as it varies between rows
  // combined the ranges that are in the same column
  var room1_roomnum_address = 'B1:B3';
  var floor_siteName = 'D2:D3';
  var siteCode = 'E3';
 
  var commissioning_template = SpreadsheetApp.openById('ID');

  // for all data to start at index 4, remove index 0 to 3 of roomlist
  roomlist.splice(0, 4);

  // loop all data remaining (this should start at 4th index which is 5th row of sheets data)
  roomlist.forEach(row => {
    // assign columns A, B, E and F each row to the following variables
    // other columns that weren't used are assigned to colC, colD, and colG
    var [sourcenum, roomname, colC, colD, sourceflr, roomtype, colG] = row;
    var copyroom = `Copy of ${roomtype}`;
    var tab = `${roomname} - ${copyroom}`;
    var tabSheet = ss.getSheetByName(tab);

    commissioning_template.getSheetByName(roomtype).copyTo(ss);
    ss.getSheetByName(copyroom).setName(tab);

    // set room1, roomnum and address at the same time
    tabSheet.getRange(room1_roomnum_address).setValues([[roomname],[sourcenum],[address]]);
    // set floor and siteName
    tabSheet.getRange(floor_siteName).setValues([[sourceflr],[sitename]]);
    // set siteCode
    tabSheet.getRange(siteCode).setValue(sitecode);
  });
}

注意:

  • 个人偏好将选项卡名称与范围分开,但分开时我更容易阅读代码。
  • 由于您正在检查do 循环,如果roomname 为空白并停在那里,我在getValues 之后使用filter 删除具有空白列B 值的行。尽管在看到空白行后,这仍然会获得 B 列中具有值的行。我假设您的数据是连续的,并且两者之间没有空白行,因此这将起作用。如果没有,请在下方评论,以便我修改。
  • splice 将永久删除指示的行。因此,鉴于我选择删除前 4 行,请在 splice 命令之前将所需的每个单元格值保存到变量中。或者,您可以修改此方法并使用 slice 代替不删除它并在之后使用 forEach 但如果我对上面的行没有用处,我更喜欢这种方法。
  • 目前,我们在forEachrow 中循环A5:G100 包含所有值。我更喜欢使用forEach,因为我不需要考虑迭代器,因为它会毫无问题地迭代数组本身。
  • 正如 Cooper 所提到的,在每个循环中读取和写入非常慢。所以我尝试将多个setValues 组合成setValues。这接受 2D 数组,因此请确保在写入之前正确格式化数据。
    • 如果将数据写入单列,数组应该是这种形式:[[A1], [A2], [A3]]
    • 如果将数据写入单行,则数组应采用以下形式: [[A1, B1, C1]]
    • 如果写入多行/多列,数组应该是这种形式:[[A1, B1, C1], [A2, B2, C2], [A3, B3, C3]]
  • 在您的情况下,我需要分隔 setValues,因为您可能在 B 列和 D 列之间有数据,它会覆盖这些值。所以我选择按列来做,这仍然是对多个 setValue 的改进

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-30
    • 2021-10-08
    • 2016-04-09
    • 2014-03-23
    相关资源
    最近更新 更多