arrays - 需要一个自定义函数来为显示的每一行重复并最小化 API 调用
问题描述
编辑:我需要帮助将功能组合成 1 并添加触发器。
在我的电子表格中,我4-100
通过选择“服务月”或“服务日”(即“7/11”仅显示 5 行“7 月”将显示)从“ServiceData”工作表中筛选出客户服务呼叫行65 行)。每个行项目在列中具有对应的起点/目的地的地点 ID,在列K
中L
具有订单号(如当天的第 1、2、3... 次服务调用)J
。
我travelTime()
在单元格中使用以下自定义函数M4:M100
来计算 2 个地点 ID 之间的行驶时间和距离:
function travelTime(origin,destination) {
var API_KEY = PropertiesService.getScriptProperties().getProperty('keyMaps');
var baseUrl = "https://maps.googleapis.com/maps/api/distancematrix/json? units=imperial&origins=";
var queryUrl = baseUrl + "place_id:" + origin + "&destinations=" +
"place_id:" + destination + "&mode=driving" + "&key=" + API_KEY;
var response = UrlFetchApp.fetch(queryUrl);
var json = response.getContentText();
var time = JSON.parse(json);
return [[ time.rows[0].elements[0].duration.text,
time.rows[0].elements[0].distance.text ]] ;
一个主要问题是,当我对“ServiceData”电子表格进行编辑时(即,当特定日期被过度安排时,服务日期会更改)并且不需要更新旅行时间,直到我按计划完成了工作。经过大量研究后,我似乎可以使用几个选项;缓存、循环、数组,并将所有内容放入脚本中,然后附加到按钮以仅在准备好时运行。考虑到我是一个新手,将所有这些选项放在一起肯定超出了我的技能水平,并且真的可以使用一些帮助。
使用新功能进行编辑:
因此,经过更多研究,我能够将以下功能放在一起,当每个功能独立运行时效果很好。现在我遇到的问题是将这些全部放在一起,特别是将原始文件调整travelTime()
为newTravelTime()
. 我已经朝着下面的正确方向进行了尝试,但不知道如何在那里进行 API 调用。
function newTravelTime() {//<--**having issues how to write this function
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName("MonthlySA");
var sourceR = sourceSheet.getRange(4, 11, sourceSheet.getLastRow()-3, 4);
var sourceV = sourceR.getValues();
var array = [];
for (var i = 0; i < sourceV.length; i++) {
if (sourceV[i][2] == "") {
var origin = sourceV[i][0];//ori place IDs for API query
var destination = sourceV[i][1];//des place IDs API api query
}
array.push([sourceV[i][2]]);
}
sourceSheet.getRange(4, 13, array.length, 1).setValues(array);
我想创建一个getTravelTime()
包含所有功能的决赛,并在单元格中的“服务月”或“服务日”更改B1
或B2
运行它们时添加一个 OnEdit 触发器。如果对我的功能本身有任何建议,我将非常感谢一些帮助,我对此非常陌生并且正在尝试。
///checks if origin/destination are already in the cacheSheet then return travel time to sourceSheet
function getCachedTravelTime() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName("MonthlySA");
var sourceR = sourceSheet.getRange(4, 11, sourceSheet.getLastRow()-3, 4);
var sourceV = sourceR.getValues();
var cacheSheet = ss.getSheetByName("TravelTimeCache");
var cacheR = cacheSheet.getRange(2, 1, cacheSheet.getLastRow()-1, 4);
var cacheV = cacheR.getValues();
var array = [];
for (var i = 0; i < sourceV.length; i++) {
for (var j = 0; j < cacheV.length; j++) {
//if origin/destination columns from sourceSheet match columns on cacheSheet
if (sourceV[i][0]+sourceV[i][1] == cacheV[j][0]+cacheV[j][1]) {
sourceV[i][2] = cacheV[j][2]; //column with travel duration
sourceV[i][3] = cacheV[j][3]; //column with travel distance
}
}
array.push([sourceV[i][2], sourceV[i][3]]);
}
sourceSheet.getRange(4, 13, array.length, 2).setValues(array);
}
///if origin or destination are blank, label as 'missing value'
function missingOD() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName("MonthlySA");
var sourceID = sourceSheet.getRange(4, 3, sourceSheet.getLastRow()-3, 12);
var sourceV = sourceID.getValues();
var array = [];
for (var i = 0; i < sourceV.length; i++) {
// if ID has a value
if (sourceV[i][0] != "") {
// if origin or destination is blank
if (sourceV[i][8] == "" || sourceV[i][9] == "") {
sourceV[i][10] = 'missing value';
}
}
array.push([sourceV[i][10]]);
}
sourceSheet.getRange(4, 13, array.length, 1).setValues(array);
}
///if cache not found - get the new travelTime for that origin/destination on sourceSheet...
function newTravelTime() {//<--
}
///...and store the new travelTime() in cacheSheet
function storeTravelTime() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName("MonthlySA");
var sourceR = sourceSheet.getRange(4, 11, sourceSheet.getLastRow()-3, 4);
var sourceV = sourceR.getValues();
var cacheSheet = ss.getSheetByName("TravelTimeCache");
var cacheR = cacheSheet.getRange(2, 1, cacheSheet.getLastRow()-1, 4);
var cacheV = cacheR.getValues();
var array = [];
for (var i = 0; i < sourceV.length; i++) {
var duplicate = false;
for (var j = 0; j < cacheV.length; j++) {
if (sourceV[i][0]+sourceV[i][1] == cacheV[j][0]+cacheV[j][1]) {
duplicate = true;
}
}
if(!duplicate){ //if origin/destination columns from sourceSheet are NOT matched on cacheSheet
array.push([sourceV[i][0], sourceV[i][1], sourceV[i][2], sourceV[i][3]]);//columns with new data
}
}
//add new data to last row of cacheSheet
cacheSheet.getRange(cacheSheet.getLastRow()+1, 1, array.length, 4).setValues(array);
}
解决方案
想到的最简单的解决方案之一是Caching
. 不是每次都进行 API 调用,而是检查我们之前是否已经进行过调用。
像这样的东西
function getTravelTime(origin, destination) {
var travelTime = getTravelTimeFromPreviousCall(origin, destination);
if (travelTime != null) {
return travelTime;
} else {
var travelTime = fetchTravelTime(origin, destination);
storeTravelTime(origin, destination, travelTime);
return travelTime;
}
}
function fetchTravelTime(origin, destination) {
var API_KEY = PropertiesService.getScriptProperties().getProperty('keyMaps');
var baseUrl = "https://maps.googleapis.com/maps/api/distancematrix/json? units=imperial&origins=";
var queryUrl = baseUrl + "place_id:" + origin + "&destinations=" + "place_id:" + destination + "&mode=driving" + "&key=" + API_KEY;
var response = UrlFetchApp.fetch(queryUrl);
var json = response.getContentText();
var time = JSON.parse(json);
return time.rows[0].elements[0].duration.text;
}
为此,我们可以定义我们的缓存,例如:
带列的工作表 -
- 起源
- 目的地
- 旅行时间
我们需要定义以下函数:
getTravelTimeFromPreviousCall(origin, destination)
:在此我们需要检查缓存并返回该出发地和目的地的旅行时间,如果没有找到则返回null
storeTravelTime(origin, destination, time)
:这将仅存储行程时间以供将来在缓存表中使用
你可以尝试这样的事情:
function getTravelTimeFromPreviousCall(origin, destination) {
var cacheSheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(CACHE_SHEET_NAME);
var cacheData = sheet.getDataRange().getValues();
for (var i=0; i<cacheData.length; i++) {
if (cacheData[i][ORIGIN_COLUMN_INDEX]==origin && cacheData[i][DESTINATION_COLUMN_INDEX]==destination) {
return cacheData[i][TRAVEL_TIME_COLUMN_INDEX];
}
}
return null;
}
function storeTravelTime(origin, destination, travelTime) {
var cacheSheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(CACHE_SHEET_NAME);
sheet.appendRow([origin, destination, travelTime]);
}
请根据您的工作表修复循环变量、数组索引和常量。
推荐阅读
- javascript - 拆分 API 以将其部分用作变量
- logging - Windows 10 IoT 核心设备门户不显示 LoggingChannel 事件
- javascript - 如何使用moment js让第二天跳过周末
- python - 哪个距离度量用于二进制值?
- sql - sql aws雅典娜(时间戳)
- php - PHP Apache 授权标头
- typescript - WebSorm 中 TypeScript 的 UML 图
- vba - 如何在我的表单的启动事件中提示 CSV 用户输入?
- php - 基本控制器中的 Destroy() 不起作用
- python - Scrapy Selenium Stale“元素不再附加到 DOM”错误