使用带有 arrayformula 的自定义公式计算 Google 表格中两列城市之间的距离
Use a custom formula with arrayformula for distances between two columns of cities in Google Sheets with App Scripts
我在 Google Apps 脚本和 Google 表格中有一个自定义公式,可以给出两个城市之间的距离。 EXAMPLE SHEET
=MILEAGE(A2,B2)
function MILEAGE(origin,destination) {
Utilities.sleep(0);
var directions = Maps.newDirectionFinder()
.setRegion('US')
.setOrigin(origin)
.setDestination(destination)
.getDirections();
var route = directions.routes[0].legs[0];
var distance = (route.distance.value) * 0.000621371;
return distance
}
该公式适用于两个单元格,但我需要它像数组公式一样适用于两行城市每行独立。我已经权衡了 运行 脚本的优缺点,一次使用一个数组并返回一个数组,但它在此应用程序中无效,因为我不希望每次一行 [= 时都重新计算整个范围29=].
objective 是这样工作的:
=arrayformula(if(A2:A<>"", MILEAGE(A2:A, B2:B), ""))
任何有关如何执行此操作的建议,或实现相同目标的更好方法,我们将不胜感激。
问题是,当您在自定义函数中使用传递范围时,它不会传递范围,而是传递值。
我建议您专门使用触发器 onEdit
这样当您编辑特定单元格时,它只会重新计算该行。我还做到了,如果您删除或添加多个位置,它们会更新相应的行。
脚本:
function onEdit(e) {
var sheet = e.source.getActiveSheet();
var range = e.range;
var row = range.getRow();
var column = range.getColumn();
var lastRow = range.getLastRow();
for(var i = 0; i <= lastRow - row; i++)
if (row + i > 1 && (column == 1 || column == 2) && sheet.getName() == "Sheet1") {
var origin = sheet.getRange(row + i, 1).getValue();
var destination = sheet.getRange(row + i, 2).getValue();
if(origin && destination)
sheet.getRange(row + i, 3).setValue(calculateMileage(origin, destination));
else
sheet.getRange(row + i, 3).clearContent();
};
}
function calculateMileage(origin, destination) {
var directions = Maps.newDirectionFinder()
.setRegion('US')
.setOrigin(origin)
.setDestination(destination)
.getDirections();
var route = directions.routes[0];
if (route) {
var legs = route.legs[0];
var distance = (legs.distance.value) * 0.000621371;
return distance;
}
else {
return "no route found"
}
}
输出:
注:
- 我发现一个单元格由于位置无效或找不到路线而 returns 出错,所以我尝试捕捉它。
- 如果某行在任一单元格中都没有值,它将删除距离列。
为了使这个函数数组兼容,
检查它是否是数组并且map它是元素
如果不是数组,直接传元素
Cache service 也可用于避免重复调用地图。
/**
* @param {string} origin
* @param {string} destination
*/
function MILEAGE_(origin, destination) {
try {
const sCache = CacheService.getScriptCache();
const key = `${origin}_${destination}`;
const cached = sCache.get(key);
if (cached) return Number(cached);
Utilities.sleep(1);
const directions = Maps.newDirectionFinder()
.setRegion('US')
.setOrigin(origin)
.setDestination(destination)
.getDirections();
const route = directions.routes[0].legs[0];
const distance = route.distance.value * 0.000621371;
sCache.put(key, String(distance), 21600);
return distance;
} catch {
return '#ERROR';
}
}
/**
* @param {A1:D1} arr
* @param {A1} param1
* @param {C1} param2
* @customfunction
*/
const mileage = (...arr) =>
Array.isArray(arr[0]) ? arr[0].map(e => MILEAGE_(...e)) : MILEAGE_(...arr);
用法:
=MILEAGE("origin","destination")
=MILEAGE(A1,B1)
=MILEAGE(A1:B100)
我在 Google Apps 脚本和 Google 表格中有一个自定义公式,可以给出两个城市之间的距离。 EXAMPLE SHEET
=MILEAGE(A2,B2)
function MILEAGE(origin,destination) {
Utilities.sleep(0);
var directions = Maps.newDirectionFinder()
.setRegion('US')
.setOrigin(origin)
.setDestination(destination)
.getDirections();
var route = directions.routes[0].legs[0];
var distance = (route.distance.value) * 0.000621371;
return distance
}
该公式适用于两个单元格,但我需要它像数组公式一样适用于两行城市每行独立。我已经权衡了 运行 脚本的优缺点,一次使用一个数组并返回一个数组,但它在此应用程序中无效,因为我不希望每次一行 [= 时都重新计算整个范围29=].
objective 是这样工作的:
=arrayformula(if(A2:A<>"", MILEAGE(A2:A, B2:B), ""))
任何有关如何执行此操作的建议,或实现相同目标的更好方法,我们将不胜感激。
问题是,当您在自定义函数中使用传递范围时,它不会传递范围,而是传递值。
我建议您专门使用触发器 onEdit
这样当您编辑特定单元格时,它只会重新计算该行。我还做到了,如果您删除或添加多个位置,它们会更新相应的行。
脚本:
function onEdit(e) {
var sheet = e.source.getActiveSheet();
var range = e.range;
var row = range.getRow();
var column = range.getColumn();
var lastRow = range.getLastRow();
for(var i = 0; i <= lastRow - row; i++)
if (row + i > 1 && (column == 1 || column == 2) && sheet.getName() == "Sheet1") {
var origin = sheet.getRange(row + i, 1).getValue();
var destination = sheet.getRange(row + i, 2).getValue();
if(origin && destination)
sheet.getRange(row + i, 3).setValue(calculateMileage(origin, destination));
else
sheet.getRange(row + i, 3).clearContent();
};
}
function calculateMileage(origin, destination) {
var directions = Maps.newDirectionFinder()
.setRegion('US')
.setOrigin(origin)
.setDestination(destination)
.getDirections();
var route = directions.routes[0];
if (route) {
var legs = route.legs[0];
var distance = (legs.distance.value) * 0.000621371;
return distance;
}
else {
return "no route found"
}
}
输出:
注:
- 我发现一个单元格由于位置无效或找不到路线而 returns 出错,所以我尝试捕捉它。
- 如果某行在任一单元格中都没有值,它将删除距离列。
为了使这个函数数组兼容,
检查它是否是数组并且map它是元素
如果不是数组,直接传元素
Cache service 也可用于避免重复调用地图。
/**
* @param {string} origin
* @param {string} destination
*/
function MILEAGE_(origin, destination) {
try {
const sCache = CacheService.getScriptCache();
const key = `${origin}_${destination}`;
const cached = sCache.get(key);
if (cached) return Number(cached);
Utilities.sleep(1);
const directions = Maps.newDirectionFinder()
.setRegion('US')
.setOrigin(origin)
.setDestination(destination)
.getDirections();
const route = directions.routes[0].legs[0];
const distance = route.distance.value * 0.000621371;
sCache.put(key, String(distance), 21600);
return distance;
} catch {
return '#ERROR';
}
}
/**
* @param {A1:D1} arr
* @param {A1} param1
* @param {C1} param2
* @customfunction
*/
const mileage = (...arr) =>
Array.isArray(arr[0]) ? arr[0].map(e => MILEAGE_(...e)) : MILEAGE_(...arr);
用法:
=MILEAGE("origin","destination")
=MILEAGE(A1,B1)
=MILEAGE(A1:B100)