【问题标题】:Google Apps Script - Improve Script to Execute FasterGoogle Apps 脚本 - 改进脚本以更快地执行
【发布时间】:2021-12-15 02:15:41
【问题描述】:

我有一张超过 3000 分(纬度、经度)的表格。我正在运行以下代码来计算每个点与 9 个参考点的距离,并在工作表中的每个点旁边写下最小距离。代码运行良好,但在运行所有点之前速度很慢并且超时。如何使以下代码更高效 - 以便更快地读取、计算和写回数据?

/*
******************************
Reference Points        
Point_A 41.166866   -76.151926
Point_B 41.087500   -76.204694
Point_C 40.540960   -75.704900
Point_D 40.401080   -75.589600
Point_E 40.326130   -75.642500
Point_F 40.167480   -75.921500
Point_G 40.093370   -76.084700
Point_H 39.974450   -76.063000
Point_I 39.722350   -76.156000
********************************
*/

var SpreadsheetID = "ABC";
var SheetName = "XYZ";

function DistanceCalculator() {
  var ss = SpreadsheetApp.openById(SpreadsheetID)
  var sheet = ss.getSheetByName(SheetName);


  //Select the column
  var columnToCheck = sheet.getRange("A:A").getValues();
  
  // Get the last row in the column
  var lastRow = getLastRowSpecial(columnToCheck);
  
  // Ref point latitude
  var Latitude_Point_A = 41.166866;
  var Latitude_Point_B = 41.087500;
  var Latitude_Point_C = 40.540960;
  var Latitude_Point_D = 40.401080;
  var Latitude_Point_E = 40.326130;
  var Latitude_Point_F = 40.167480;
  var Latitude_Point_G = 40.093370;
  var Latitude_Point_H = 39.974450;
  var Latitude_Point_I = 39.722350;

  // Ref point longitude
  var Longitude_Point_A = -76.151926;
  var Longitude_Point_B = -76.204694;
  var Longitude_Point_C = -75.704900;
  var Longitude_Point_D = -75.589600;
  var Longitude_Point_E = -75.642500;
  var Longitude_Point_F = -75.921500;
  var Longitude_Point_G = -76.084700;
  var Longitude_Point_H = -76.084700;
  var Longitude_Point_I = -76.156000;
  
  for( var i=1; i<=lastRow;i++){
    //Reading Lat_Long from the sheet
    var Lat_Check = sheet.getRange(i,2).getValue();
    var Long_Check = sheet.getRange(i,3).getValue();

    //Calculating distance between each point and reference points
    var distance01 = calculateDistance(Latitude_Point_A,Longitude_Point_A,Lat_Check,Long_Check);
    var distance02 = calculateDistance(Latitude_Point_B,Longitude_Point_B,Lat_Check,Long_Check);
    var distance03 = calculateDistance(Latitude_Point_C,Longitude_Point_C,Lat_Check,Long_Check);
    var distance04 = calculateDistance(Latitude_Point_D,Longitude_Point_D,Lat_Check,Long_Check);
    var distance05 = calculateDistance(Latitude_Point_E,Longitude_Point_E,Lat_Check,Long_Check);
    var distance06 = calculateDistance(Latitude_Point_F,Longitude_Point_F,Lat_Check,Long_Check);
    var distance07 = calculateDistance(Latitude_Point_G,Longitude_Point_G,Lat_Check,Long_Check);
    var distance08 = calculateDistance(Latitude_Point_H,Longitude_Point_H,Lat_Check,Long_Check);
    var distance09 = calculateDistance(Latitude_Point_I,Longitude_Point_I,Lat_Check,Long_Check);


    //measuring minimum distance
    var minimumDistance = Math.round(Math.min(distance01,distance02,distance03,distance04,distance05,distance06,distance07,distance08,distance09))

    sheet.getRange(i,4).setValue(minimumDistance); 

  }
  
}


function calculateDistance(Ref_Lat, Ref_Long, Looped_Lat, Looped_Long){

  var p = 0.017453292519943295;    // Math.PI / 180
  var c = Math.cos;
  var a = 0.5 - c((Looped_Lat - Ref_Lat) * p)/2 + 
          c(Ref_Lat * p) * c(Looped_Lat * p) * 
          (1 - c((Looped_Long - Ref_Long) * p))/2;
  var result = 7926 * Math.asin(Math.sqrt(a)); // 2 * R; R = 3963 miles
  return result
};


function getLastRowSpecial(range){
  var rowNum = 0;
  var blank = false;
  for(var row = 0; row < range.length; row++){
 
    if(range[row][0] === "" && !blank){
      rowNum = row;
      blank = true;
    }else if(range[row][0] !== ""){
      blank = false;
    };
  };
  return rowNum;
};

Sample Spreadsheet Screenshot

【问题讨论】:

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


    【解决方案1】:

    我相信你的目标如下。

    • 您希望降低脚本的处理成本。

    在您的脚本中,getValuesetValue 在循环中使用。我认为这可能是您的问题的原因。在这种情况下,首先从工作表中检索值并处理这些值,然后将这些值放入工作表中。该流程适用于降低工艺成本。我认为“最佳实践”将有助于理解您的问题。 Ref

    另外,我认为当您的脚本的处理成本降低时,可能需要一点独创性来修改您的脚本。所以我提出几个修改后的脚本之一作为参考。请按如下方式修改您的脚本。

    发件人:

    for( var i=0; i<lastRow;i++){
      //Reading Lat_Long from the sheet
      var Lat_Check = sheet.getRange(i,2).getValue();
      var Long_Check = sheet.getRange(i,3).getValue();
    
      //Calculating distance between each point and reference points
      var distance01 = calculateDistance(Latitude_Point_A,Longitude_Point_A,Lat_Check,Long_Check);
      var distance02 = calculateDistance(Latitude_Point_B,Longitude_Point_B,Lat_Check,Long_Check);
      var distance03 = calculateDistance(Latitude_Point_C,Longitude_Point_C,Lat_Check,Long_Check);
      var distance04 = calculateDistance(Latitude_Point_D,Longitude_Point_D,Lat_Check,Long_Check);
      var distance05 = calculateDistance(Latitude_Point_E,Longitude_Point_E,Lat_Check,Long_Check);
      var distance06 = calculateDistance(Latitude_Point_F,Longitude_Point_F,Lat_Check,Long_Check);
      var distance07 = calculateDistance(Latitude_Point_G,Longitude_Point_G,Lat_Check,Long_Check);
      var distance08 = calculateDistance(Latitude_Point_H,Longitude_Point_H,Lat_Check,Long_Check);
      var distance09 = calculateDistance(Latitude_Point_I,Longitude_Point_I,Lat_Check,Long_Check);
    
    
      //measuring minimum distance
      var minimumDistance = Math.round(Math.min(distance01,distance02,distance03,distance04,distance05,distance06,distance07,distance08,distance09))
    
      sheet.getRange(i,4).setValue(minimumDistance); 
    
    }
    

    收件人:

    var values = sheet.getRange("B1:C" + lastRow).getValues();
    var ar = [[Latitude_Point_A, Longitude_Point_A], [Latitude_Point_B, Longitude_Point_B], [Latitude_Point_C, Longitude_Point_C], [Latitude_Point_D, Longitude_Point_D], [Latitude_Point_E, Longitude_Point_E], [Latitude_Point_F, Longitude_Point_F], [Latitude_Point_G, Longitude_Point_G], [Latitude_Point_H, Longitude_Point_H], [Latitude_Point_I, Longitude_Point_I]];
    var res = values.map(([b, c]) => [Math.round(Math.min(...ar.map(e => calculateDistance(...e, b, c))))]);
    sheet.getRange(1, 4, res.length).setValues(res);
    
    • 在此修改中,根据您的脚本,它假定第一行不是标题行。请注意这一点。
    • 在此修改中,getValues 从工作表中检索值,然后由setValues 计算检索到的值并将其放入工作表中。

    注意:

    • 当我看到你的脚本时,我认为var Lat_Check = sheet.getRange(i,2).getValue(); 出现错误,因为i 的第一个值是0。而在函数calculateDistance中,Ref_Lat, Ref_Long没有被使用。所以我担心您的放映脚本可能与您遇到问题的脚本不同。因此,当您测试上述修改时,当出现错误时,您能否确认您的显示脚本是否是适合您情况的正确脚本。并且,请提供用于将问题复制为图像的示例电子表格。借此,我想确认一下。

    参考资料:

    【讨论】:

    • 感谢您的回复,您的推荐看起来很有希望,准备试试。同时,我已经更正了您指出的代码中的错误并添加了电子表格的屏幕截图。
    • @RF919 感谢您回复并提供示例图片。从您的示例图像中,我了解到这些值是从第 1 行放置的。由此,我认为我提出的脚本可能可以使用。如果我提出的脚本没有用,我深表歉意。
    • 您提出的脚本准确地解决了我面临的问题。早些时候,我的脚本将运行 30 分钟并超时,而不会遍历所有行,根据您提出的更改,它会在几秒钟内完全执行!感谢您的帮助。
    • @RF919 感谢您的回复和测试。我很高兴你的问题得到了解决。也谢谢你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多