分享

如何查找第一次发生改变的日期和金额 - Excel函数式编程

 ExcelEasy 2023-07-24 发布于北京


今天介绍一个实际的Excel案例。

很多人有一个错误的印象:使用Excel函数式编程解决问题比以前单纯的使用Excel公式更难。其实这是一个很典型的误解。就绝大多数问题而言,使用函数式编程从思路到实现都更容易掌握。

而且,无论是使用传统的Excel公式,还是使用函数式编程,二者从思路上是一致的。但是因为在传统的解决方案中,你必须花费大量时间和精力去思考如何编写“巧妙”的公式,导致大部分人忽略了解决思路的重要性。

问题

先来看具体的问题:

上表中记录了不同人员在不同月份的累计订购金额。

要求:针对每人,求出销售额首次发生变动的月份和金额。比如,对于B来说,202203是发生变动的月份,金额是72。

在解决这类问题时,第一件事是明确需求。上面的要求是经过极度简化的,据此设计的方案很可能不能满足问题提出者的真实需求。所以,我们需要给出最终的样表,

解决思路

无论使用什么样的技术方案,第一件事是设计解决思路,而不是匆匆忙忙开始编写“巧妙”的公式。

我们将问题简化一下,只考虑1个用户的情形,

并没有特别简单的公式可以让我们从这一行数字中迅速发现第一个72。

但是,如果我们变化一下数据,

显然,后一份数据是根据前一份数据中后一个月份减去前一个月份得来。

现在,我们非常容易可以迅速定位第一个发生变化的数据了,因为它是整行数据中第一个不为0的数据。

很简单,就是一个简单的MATCH函数应用。

作为参考,这个公式可以这么写:

=MATCH(TRUE,D13:N13<>0,0)

这个公式返回的是位置。根据这个位置,自然可以很容易得到想要的结果,只要一个简单的INDEX函数即可:

传统Excel公式的方案

有了上面的思路,如果使用以前的公式思路进行解决,当然离不了辅助列和辅助表,

上图中演示了如何使用MATCH函数和INDEX函数完成这个需求。诀窍在于添加了辅助表A11:N18,以及辅助列O12:O18。

函数式编程方案

而使用函数式编程来解决这个问题,思路一模一样,却只要一个公式即可完成,不需要中间的辅助表和辅助列,

=LET(    srcdata, A1:N8,    months, DROP(TAKE(srcdata, 1), , 1),    Names, DROP(TAKE(srcdata, , 1), 1),    dataArray, DROP(srcdata, 1, 1),    changes, MAKEARRAY(        ROWS(Names),        3,        LAMBDA(r, c,            LET(                curRow, CHOOSEROWS(dataArray, r),                prefix, DROP(curRow, , -1),                suffix, DROP(curRow, , 1),                diff, HSTACK(0, suffix - prefix),                idx, MATCH(TRUE, diff <> 0, 0),                IFS(                    c = 1,                    CHOOSECOLS(months, idx),                    c = 2,                    CHOOSECOLS(curRow, idx),                    c = 3,                    CHOOSECOLS(diff, idx)                )            )        )    ),    IFERROR(changes, ""))

这个公式看似复杂,但是逻辑清晰,简单,只要根据我们前面分析的思路逐步实现即可。首先,整个过程分为两步。红色部分是将数据区域进行划分,共分为三部分:

months - 首行,即各月份;

names - 首列,即用户姓名;

dataArray - 即数据区域;

绿色部分是具体实现。整个过程是通过MAKEARRAY函数循环处理每一个用户,所以需要对names数组进行循环,生成3列,分别是首次改变日期,金额,以及变化的差额。

循环中,对当前循环到的用户,首先取出当前的数据,即curRow,

然后将前面11个月和后面11个月的数据分别取出,即prefix,suffix,

然后计算差额diff,suffix - prefix只有11个数,所以前面加上0 补足12个数,

然后用在diff中找到第一个不为0的位置,

然后通过IFS函数分别取出3列结果数据,其中的CHOOSECOLS函数可以用INDEX函数代替。

深入

最后,我们再想得更多一些:如果我们找的不是首次发生变化,而是要找到所有发生变化的日期和金额,

即,需要得到如下的结果表格,

又应该怎么做呢?


    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多