【问题标题】:Evaluate a sub-formula of a formula计算公式的子公式
【发布时间】:2016-07-12 12:49:48
【问题描述】:

选择一个有公式的单元格后,我们可以在Excel公式栏中选择其公式的一部分并计算它(按F9)。我需要通过 JavaScript API 重现这种对子公式的评估。

例如,假设单元格A1B1C1 的值分别为123,并且单元格D1 包含一个公式=A1+B1+C1。我希望能够快速评估A1+B1B1+C1 等子公式,并得到结果35

在VBA中,manual计算模式下,我们可以将D1的初始公式存储在一个变量中,然后将一个子公式(如=A1+B1)赋值给D1得到结果@ 987654337@,然后将初始公式恢复为D1,就像什么都没发生一样;此评估不会引发对 D1 后代的任何其他单元格的计算(感谢 manual 模式)。

但是,对于 JavaScript API,重新计算仅适用于 automatic 模式。如果我们为D1分配一个子公式(例如=A1+B1),那么所有D1的后代单元格都会被ctx.sync重新计算,这可能会很昂贵。

那么有没有办法或解决方法来优化它?

一种可能的解决方法是在工作簿中找到一个没有单元格依赖的孤立单元格(例如,工作表的 usedRange 之外的单元格,但我们仍然需要确保没有单元格依赖它,因为性质usedRange...),然后将子公式分配给该单元格并获取值。这种方法的缺点是

1) 它仍然是一个 hack,并且会修改工作表的区域。

2) 用户定义的函数(如果编程不当)可能依赖于工作表的尺寸或保存它的单元格的位置。在这种情况下,在孤立的单元格中评估用户定义的函数可能会导致与原始单元格中的评估不同的结果(或副作用)。

有人可以帮忙吗?

【问题讨论】:

  • 我有兴趣详细了解您正在构建的这个加载项,它使用了如此多的功能和 API 特性。如果您想演示或分享您的想法,请通过 exceladdins@outlook.com 与我联系,我将提供我的工作电子邮件地址。谢谢!
  • 感谢您的关注,感谢@MichaelZlatkovsky 不断回答我的问题。我认为能够直接向 Microsoft 团队发表讲话并非常感激,这是一种荣幸。其实我之前在OCaml中开发过一个“引擎”,1个月来一直在开发Excel JavaScript插件作为“接口”;我已经提交了 2 个,并且正在开发第三个(因此并非所有功能都在一个插件中)。当我认为我的外接程序看起来不错时,我会尽快与您联系,并且很高兴与你们继续密切(和远程)合作......

标签: ms-office office-js


【解决方案1】:

我认为您列出的第一种方法可能是最简单的。即,重新读取单元格的公式并将其保存为 javascript 变量(字符串)。接下来修改公式,对值发出负载,然后将公式恢复为保存字符串。这种方法唯一真正的缺点是你弄乱了某人的公式,这意味着如果在第 1 步和第 2 步之间出现问题,你会使文档处于肮脏状态。而且,正如您所说,它可能会对计算产生下游影响(性能方面)。

或者,如果您确实知道那里有哪些公式,您可以使用“工作表函数”功能。例如,您在这里计算 20 的总和 + 两个工作表范围的总和。

Excel.run(function (ctx) {
    var result = ctx.workbook.functions.sum(
        20,
        ctx.workbook.worksheets.getItem("Sheet1").getRange("F3:F5"),
        ctx.workbook.worksheets.getItem("Sheet1").getRange("H3:H5")
    ).load();

    return ctx.sync();
}).catch(function(e) {
    console.log(e);
});

这是“最干净”的计算方式,它不会影响工作表状态,您甚至可以链接计算:

Excel.run(function (ctx) {
    var range = ctx.workbook.worksheets.getItem("Sheet1").getRange("E2:H5");

    var sumOfTwoLookups = ctx.workbook.functions.sum(
        ctx.workbook.functions.vlookup("Wrench", range, 2, false),
        ctx.workbook.functions.vlookup("Wrench", range, 3, false)
        );
    sumOfTwoLookups.load();

    return ctx.sync();
}).catch(function(e) {
    console.log(e);
});

缺点是这不适用于 UDF(以及数组公式,就此而言),并且您需要先验地知道单元格由哪种公式组成。但是,如果您正在谈论计算公式的子公式,我假设您已经掌握了有关公式的一些信息,因此后者可能不是问题。

【讨论】:

  • 好吧,这很有趣,我不知道“工作表函数”...我没有找到-/+* 的函数(而不是使用 SUM、PRODUCT 等变通方法)。如果它们不存在,看来我们必须做两次ctx.sync才能实现SUM(1,SUM(3,4)-2),因为我们不能直接写var result = ctx.workbook.functions.sum(1,ctx.workbook.functions.sum(3,4)-2)...
  • 我问过another question...
  • 对于这种情况和许多其他情况,真正需要的是等效于 VBA Application.Evaluate 和 Worksheet.Evaluate(最好比 VBA 评估少一些错误)
  • @Charles,我同意如果可以的话,这将是理想的。但实际上Application.Evaluate 与 VBA/桌面实现非常相关(并且还允许您评估在其他平台上无效的公式,和/或依赖于其他已打开书籍的公式(这也不会为诸如网络之类的东西工作)等)。因此,至少作为第一步,仅隔离纯函数是更可行的任务。
  • @Michael - 不确定这是否正确 - 我的理解是 Evaluate 只是挂钩到 Excel 的公式解释器/评估器 - 它存在于所有平台上。而且我不知道任何仅在某些平台上有效的有效 Excel 公式 - 你能举个例子吗?
猜你喜欢
  • 2020-05-24
  • 1970-01-01
  • 2018-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-13
  • 2011-12-05
  • 2017-06-16
相关资源
最近更新 更多