我习惯使用 VLOOKUP,但这次我遇到了一个挑战。我不想要第一个匹配的值,但是最后的。怎么样?(我正在使用 LibreOffice Calc,但 MS Excel 解决方案应该同样有用。)
原因是我有两个包含数千行的文本列,假设一个是交易收款人列表(亚马逊、Ebay、雇主、杂货店等),另一个是支出类别列表(工资、税金、家庭、租金等)。有些交易每次的支出类别并不相同,我想获取最近使用的类别。请注意,列表不按任何列排序(实际上是按日期排序),我不想更改排序顺序。
我所拥有的(不包括错误处理)是通常的“首次匹配”公式:
=VLOOKUP(
[payee field] , [payee+category range] , [index of category column] ,
0 )
我见过解决方案像这样,但是我收到#DIV/0!
错误:
=LOOKUP(2 , 1/( [payee range] = [search value] ) , [category range] )
解决方案可以是任何公式,不一定是 VLOOKUP。我还可以交换收款人/类别列。请不要更改排序列。
解决方案选择最频繁值,而不是最后一个!
答案1
您可以使用数组公式从最后一个匹配的记录中获取数据。
=INDEX(IF($A$1:$A$20="c",$B$1:$B$20),MAX(IF($A$1:$A$20="c",ROW($A$1:$A$20))))
Ctrl使用+ Shift+输入公式Enter。
其工作原理类似于INDEX
/MATCH
构造VLOOKUP
,但使用条件MAX
代替MATCH
。
请注意,这假设您的表格从第 1 行开始。如果您的数据从不同的行开始,则需要ROW(...)
通过减去顶行和 1 之间的差值来调整部分。
答案2
(这里回答的是,对于排序数据没有单独的问题。)
如果数据是排序后,您可以使用VLOOKUP
参数(或range_lookup
省略TRUE
,因为它是默认值),它在 Excel 中正式描述为“搜索近似匹配”。
换句话说,对于排序后的数据:
- 设置最后一个参数
FALSE
返回第一的价值,以及 - 设置最后一个参数
TRUE
返回最后的价值。
这在很大程度上没有记录且晦涩难懂,但可以追溯到 VisiCalc (1979),如今至少在 Microsoft Excel、LibreOffice Calc 和 Google Sheets 中仍然有效。这最终归因于LOOKUP
VisiCalc 中的初始实现(以及随后的VLOOKUP
和HLOOKUP
),当时没有第四个参数。该值通过以下方式找到二分查找,使用包含左边界和排他右边界(一种常见且优雅的实现),从而导致这种行为。
从技术上讲,这意味着从候选区间开始搜索[0, n)
,其中n
是数组的长度,循环不变条件是A[imin] <= key && key < A[imax]
(左边界<=目标,右边界从末尾开始,>目标;要验证,请检查之前端点的值,或检查之后的结果),然后依次二分并选择保留此不变量的一侧:通过排除,一侧将保留,直到您获得具有 1 个项的区间,[k, k+1)
然后算法返回k
。这不必是精确匹配(!):它只是来自下方的最接近匹配。如果有重复匹配,则返回最后的匹配,因为它要求下一个值是更大而不是键(或数组的末尾)。如果有重复项,你需要一些行为,这是合理且易于实现的。
此行为在旧的 Microsoft 知识库文章(强调添加)中明确说明:“XL:如何返回数组中的第一个或最后一个匹配项”(Q214069):
您可以使用 LOOKUP() 函数在已排序的数据数组中搜索某个值,并返回另一个数组中该位置所包含的相应值。如果查找值在数组中重复,它返回遇到的最后一个匹配项。此行为对于 VLOOKUP()、HLOOKUP() 和 LOOKUP() 函数均适用。
以下是一些电子表格的官方文档;其中都没有说明“最后匹配”行为,但它在 Google 表格文档中有所暗示:
答案3
如果搜索数组中的值是连续的(即,您要查找最大值,例如最新日期),则甚至不需要使用 INDIRECT 函数。尝试以下简单代码:
=MAX(IF($A$1:$A$20="c",$B$1:$B$20,)
再次使用 CTRL + SHIFT + ENTER 输入公式
答案4
我尝试了最常用的值。不确定它是否能在 libreOffice 中工作,但它似乎在 excel 中工作
=INDEX($B$2:$B$9,MATCH(MAX(--($A$2:$A$9=D2)*COUNTIFS($B$2:$B$9,$B$2:$B$9,$A$2:$A$9,D2)),--($A$2:$A$9=D2)*COUNTIFS($B$2:$B$9,$B$2:$B$9,$A$2:$A$9,D2),0))
A 列是收款人,B 列是类别,D2 是您要筛选的收款人。我不确定为什么上面的函数中要添加额外的换行符。
查找最后一个单元格的函数如下:
=INDIRECT("B" & MAX(--($A$2:$A$9=D2)*ROW($A$2:$A$9)))
间接让我指定我想要返回的列并直接找到行(所以我不需要减去标题行的数量。
这两个函数都需要使用Ctrl+Shift+回车