今天我们讨论一下LET函数的计算速度问题。 出乎意料的是,LET函数对公式计算速度的影响是个双刃剑。 我以前介绍过,使用LET函数的好处之一,就是提高计算速度。(强烈推荐你使用的Excel函数:LET) 如果一个公式中有某一个部分需要反复计算,就可以使用LET函数提高计算速度。 例如,下面这种形式的公式: =IF(func,func,1) 在一个IF公式中,条件参数是一个公式:func,如果这个公式返回结果为true,Excel就返回第二个参数:func。 这里的func就被计算了两次。 如果func本身的计算量特别大,对计算速度的影响就会很大。 就可以用LET函数改进。 为此,我们考虑一个计算量特别大的公式: =MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c)) 这个公式生成一个巨大的数组,在我的机器上,运行它需要大约1.28秒的时间,这个速度很慢了, 我们对这个数据进行计数, =COUNTA(MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c))) 这是为了在IF函数中使用它。这个公式的主要时间就是中间的那个巨大数组产生的。 我们使用下面的公式, =IF( COUNTA(MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c)))>1, COUNTA(MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c))), 0) 如果上面的计数大于1,就返回数组计数结果,否则返回1。 这个公式需要计算两次计数,所以需要接近两倍的时间, 为此,我们使用LET函数改进它, =LET( a, MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c)), b, COUNTA(a), IF(b > 1, b, 0)) 第二行,我们生成了巨大数组。以后各行,不再做这个耗时的操作了。 所以,我们只用了一次计算的时间, 另一方面,LET函数会降低计算速度。 考虑下面的公式, =IF( 0, COUNTA(MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c))), 0) 如果条件满足,就返回第二个参数(那个非常耗时的计算),否则,就返回0。 但是,第一个条件参数为0,所以,直接返回第三个参数:0,而不会处理第二个参数,也就几乎不需要任何计算时间, 但是,我们将这个公式用LET函数改写, =LET( a, MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c)), b, COUNTA(a), IF(0, b, 0)) 改写后的公式仍然需要1.28秒左右的时间, 计算反而变慢了! 这说明了一个很容易被人忽略的事实,在LET公式中所有出现过的计算,不管在最终的结果中需不需要,都会被计算出来。 我们看下面的LET公式, =LET( a, MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c)), 100) 第二行,定义了一个变量a,其值是那个特别耗时的巨大数组。 但是我们最终返回了一个常量:100,根本没有用到这个计算。 按照我们一般的理解,这里应该不会花时间进行计算。(在其他函数式编程的语言中,这一点是成立的,比如M语言) 但是,这个公式计算速度很慢, 说明Excel实际上进行了这个计算。 这就很糟糕了! 我们在LET公式中经常会把各种有可能用到的计算做成中间变量,但是最终返回值根据不同的情况返回其中的变量。 但是这样一来,那些在最终返回中没有出现的中间变量全部变成了浪费时间的负面因素了。 不仅仅如此,考虑下面的公式, =LET( a, MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c)), b, a, c, a, d, a, e, a, f, a, g, a, h, a, i, a, j, a, 100) 这个公式的结果跟上一个一样。但是多了很多无用的中间变量,每个变量都直接等于变量a。 按照LET函数的计算规则,只有第二行才会花费时间计算那个巨大数组,后面用到就是引用而已,不会参与计算,不会浪费时间。 但是,实际的计算时间是这样的, 看上去,确实只花了一次计算数组的时间,但是,那些无用的中间变量仍然需要花时间处理,并且花的时间不可忽视。 如果必须将那些用不到的计算放到中间变量中,可以将其包装成一个自定义函数: =LET( a,LAMBDA(MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c))), 100) 这里的 LAMBDA(MAKEARRAY(4000, 1000, LAMBDA(r,c, r + c))) 就是一个自定义函数。它不需要参数,调用它就是生成那个巨大数组, a() 由于我们的公式中并没有调用它,所以它就不再花费时间了, |
|