【问题标题】:Optimize for-loop function in Google Apps Script (Arrays maybe)?优化 Google Apps 脚本中的 for-loop 函数(可能是数组)?
【发布时间】:2020-01-09 05:57:44
【问题描述】:

第一次在这里发布海报。我想了解一些我认为可以修饰一下的 Google App Script 代码。

长话短说。

我有 2 个 Google Sheet 表格

  • “LOCALE”电子表格 - 列出位置的唯一名称

  • “FEED”电子表格 - 列出照片说明,包括位置。此电子表格中多次列出同一地点。

  • 这两个表都有一个“Location”列,通过Key相互引用strong> 列。

我要解决的问题:

当我在“LOCALE”电子表格中编辑地点名称时,它应该会自动更新“FEED”电子表格中的所有地点名称。

我解决这个问题的方法:

为此,我在 for 循环中使用了 for 循环。总结一下:

  • 对于“LOCALE”中的每一行...
  • ..遍历“FEED”中的每一行...
  • ...如果 FEED 表中 Key 列中的值与 表中 Key 列中的值匹配LOCALE 工作表...
  • ...但是 FEED 表中 Location 列中的值与表中 Location 列中的值不匹配LOCALE 表格...
  • ...用 LOCALELocation 列中的值更新 FEED 表中的 Location 列em> 工作表。

如果你还不明白,下面是我为它写的代码:

// for each row in the "Locale" sheet... 
for(var L = LocationsRefValues.length-1;L>=0;L--) {

  // for each row in the "Feed" sheet...
  for(var F = FeedRefValues.length-1;F>=0;F--) {

    if (FeedRefValues[F][97] == LocationsRefValues[L][17] && 
        FeedRefValues[F][10] != LocationsRefValues[L][1]) {
       FeedDataSheet.getRange(F+2,10+1).setValue(LocationsRefValues[L][1]);
    }       
  }
}

现在,这段代码运行良好,我没有遇到任何问题。但是,我觉得这有点笨拙,因为完成编辑需要一段时间。我确信有更简单的方法来编写和运行这段代码。我听说数组可以解决这种情况,但我不知道该怎么做。因此,我为什么要寻求帮助。有人可以帮忙吗?

请记住,我是一个完全的 Google App Script 初学者,完全是靠运气才得到这段代码的,所以解决方案越简单越好。感谢您提前考虑我的问题。期待大家的来信。

这是完整的功能(在我在这里建议进行编辑之后。)

   function ModeratorStatus() {

  var Data = SpreadsheetApp.getActiveSpreadsheet(); // Local Spreadsheet

  var ModeratorStatusDataSheet = Data.getSheetByName("The Status (Moderators)");
  var ModeratorStatusRange = ModeratorStatusDataSheet.getRange("A2:C");
  var ModeratorStatusRefValues = ModeratorStatusRange.getValues();

 var ModeratorDataSheet = Data.getSheetByName("The Moderator_Numbers");  // DATA "Member" sheet
  //var ModeratorRefValues = ModeratorDataSheet.getRange("A2:AD").getValues();

  var ModeratorStatusObj = {};
for (var MOS = ModeratorStatusRefValues.length-1; MOS>=0; MOS--) {
  ModeratorStatusObj[ModeratorStatusRefValues[MOS][2]] = ModeratorStatusRefValues[MOS][0];
}
  var ModeratorValues = ModeratorDataSheet.getRange("A1:AD").getValues();
for (var MO = ModeratorValues.length-1; MO >=0; MO--) { // for each row in the "Moderator" sheet...
  var ModeratorVal28 = ModeratorValues[MO][28];
  if (ModeratorStatusObj[ModeratorVal28] != ModeratorValues[MO][1]) {

    ModeratorValues[MO][1] = ModeratorStatusObj[ModeratorVal28];
  }
}
var destinationRange = ModeratorDataSheet.getRange(1, 1, ModeratorValues.length, ModeratorValues[0].length);
destinationRange.setValues(ModeratorValues);

我在不同的函数中使用了代码作为测试。为了方便

语言环境 = 版主状态

饲料 = 版主

【问题讨论】:

  • for(var C =,是不是打错字了,你是说for(var L =吗?
  • 您考虑过使用查找和替换吗? stackoverflow.com/questions/26480857/…
  • 是的,那是在我的复制/粘贴过程中。谢谢! @CertainPerformance
  • ModeratorValues[MO + 2][1 + 1]:这是什么意思?数组从 0 开始,不需要偏移量:ModeratorValues[MO][1 + 1]
  • 不要不断地使用新代码编辑问题以尝试获得解决不同错误的帮助。如果其中一个答案为原始问题提供了有用的解决方案,请接受它,然后ask a new, good question(并在其中引用这个)。

标签: javascript arrays for-loop google-apps-script google-sheets


【解决方案1】:

如果LocationsRefValues中没有与不同 [1]s重复的[17]s,则可以通过创建映射对象将计算复杂度从O(n ^ 2)降低到O(n)对于LocationsRefValues,其键为LocationsRefValues[L][17]s,其值为LocationsRefValues[L][1]s:

var locationObj = {};
for (var L = 0; L < LocationsRefValues.length; L++) {
  locationObj[LocationsRefValues[L][17]] = LocationsRefValues[L][1];
}
for (var F = FeedRefValues.length - 1; F >= 0; F--) { // for each row in the "Feed" sheet...
  var feedVal97 = FeedRefValues[F][97];
  if (locationObj[feedVal97] != FeedRefValues[F][10]) {
    FeedDataSheet.getRange(F + 2, 10 + 1).setValue(locationObj[feedVal97]);
  }
}

感谢@TheMaster,您可以在最后只调用一次setValue 来加快速度,而不是在循环中调用它,可能类似于:

var locationObj = {};
for (var L = 0; L < LocationsRefValues.length; L++) {
  locationObj[LocationsRefValues[L][17]] = LocationsRefValues[L][1];
}
var feedValues = FeedDataSheet.getValues();
for (var F = FeedRefValues.length - 1; F >= 0; F--) { // for each row in the "Feed" sheet...
  var feedVal97 = FeedRefValues[F][97];
  if (locationObj[feedVal97] != FeedRefValues[F][10]) {
    feedValues[F + 2][10 + 1] = locationObj[feedVal97];
  }
}
var destinationRange = ss.getRange(1, 1, feedValues.length, feedValues[0].length);
destinationRange.setValues(feedValues);

【讨论】:

  • @Dona 另外,避免setValue() 在循环中。见this。您应该将整个修改后的表格重新创建为二维数组,并一次性使用setValues()
  • @TheMaster 在这一行出现错误 feedValues[F + 2][10 + 1] = locationObj[feedVal97];无法将 undefined 的属性“2.0”设置为“不再支持该组织的以前的 mod,可能是由于条款不好”。 (第 2214 行,文件“上下文应用程序代码”)[0.533 秒总运行时间]另外,必须更改其中一个括号,看起来输入错误
  • @Dona 编辑您的问题以显示最新代码和错误
  • @TheMaster 我用修改后的代码和错误编辑了我的问题。有什么想法吗?
  • @TheMaster 此外,错误表明它正在比较主持人状态中名称列右侧的一个单元格(B 列,而不是 A 列)。当我只更改名称列(第一列)中的值时,显示的文本字符串位于第二列中
【解决方案2】:

您可以使用onEdit(e) 触发器来获取对已编辑单元格的引用。在这种情况下,您不需要遍历整个 Locale" 表:

function onEdit(e) {
  var range = e.range; // edited cell
  var rowIndex = range.getRow()
  var colIndex = range.getColumn()
  if (rowIndex >= LocaleRange.startRow && rowIndex <= LocaleRange.EndRow && 
      colIndex >= LocaleRange.startColumn && colIndex <= LocaleRange.EndColumn) {
    var index = rowIndex - LocaleRange.startRow
    var keyValue = LocationsRefValues[index][17]
    var newLocValue = range.getValue()
    var newFeedValues = FeedRefValues.map(function (row) {
       return (row[97] == keyValue)  newLocValue ? : row[10]
    })
    FeedDataRange.setValues(newFeedValues)
  }
}

这里是关于使用 onEdit 触发器的文档:https://developers.google.com/apps-script/guides/triggers

【讨论】:

  • 感谢@Дмитро Булах的快速回复!不幸的是, onEdit 函数不能满足我的需要。为了让我的解释简短,我没有提到我正在使用第 3 方应用程序来编辑 Google 电子表格。该应用程序的编辑不会触发 onEdit 函数,因此我必须使用定时触发器定期运行我的脚本。考虑到这一点,是否可以修改此脚本以在基于时间的触发器中使用?
  • 如果您不能使用onEdit 触发器,那么您将不得不遍历所有行并且无法对其进行优化。在这种情况下,您可以获得的唯一显着改进是使用 setValues 进行批量更新
猜你喜欢
  • 2020-01-31
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 2018-12-22
  • 1970-01-01
  • 2012-06-27
  • 1970-01-01
  • 2021-12-17
相关资源
最近更新 更多