表 ArrayFormula。按组查找最近的数字

Sheets ArrayFormula. Find nearest number by group

主数据

组值对

1 |  1
1 |  2
1 |  3
2 |  5
2 |  8
3 | 10
3 | 12

工作数据

组值对 + 期望的结果

1 | 4 | 3 (3≤4, max in group 1)
1 | 2 | 2 (2≤2, max in group 1)
2 | 6 | 5 (5≤6, max in group 2)
3 | 7 | no result (both 10 and 12 > than 7)

任务是从一组中找到最大可能匹配的数字,该数字应小于或等于给定的数字。

对于Group 1, value 4

=> filter Master Data (1,2,3) => find 3

做一次就没问题,需要用arrayformula做。

我尝试使用 vlookup 公式的修改来解决它,但到目前为止输出错误。

样本和我的工作“舞台”:

https://docs.google.com/spreadsheets/d/11Cd2BGpGN-0h2bL0LQ_EpIDBKKT2hvTVHoxGC6i8uTE/edit?usp=sharing

注意:不需要用单个公式求解,因为它可能会减慢结果。

我的解决方案基于逐行查找最大数的技术。示例公式在这里: https://docs.google.com/spreadsheets/d/1VY157ykKsCVDqEKDBp3oAVaG0LTXAz8wUCggCrFXMDM/edit#gid=628408999

我的整个解决方案在这里:

https://docs.google.com/spreadsheets/d/11Cd2BGpGN-0h2bL0LQ_EpIDBKKT2hvTVHoxGC6i8uTE/edit#gid=0

第 1 步

从大师Table.

获取按组加入号码
1 | 3,2,1
2 | 8,5
3 | 12,10

offset实现了这个↑。并使用 vlookup 将此 semi-result 与工作 table.

相匹配

第 2 步

使用if + split检查结果值是否≤我的工作值,并在同一公式中使用查询查找每行的最大值。

撰写查询:使用 join + sequence

=IF(M3=0,,"select "&JOIN(", ",INDEX("max(Col"&SEQUENCE(M3)&")")))

结果:

select max(Col1), max(Col2), max(Col3), max(Col4), max(Col5)

找到每组的最大值:

=index(TRANSPOSE(QUERY(TRANSPOSE(data), "select ...")))

这个最终公式是解决问题的方法。

注意:结果:我的公式的 0 表示“不匹配”。这对我来说很好。

尝试:

=INDEX(IFNA(IF(E4:E>=
 VLOOKUP(D4:D&TEXT(E4:E, "00000"), {A4:A&TEXT(FILTER(B4:B, B4:B<>""), "00000"), B4:B}, 2), 
 VLOOKUP(D4:D&TEXT(E4:E, "00000"), {A4:A&TEXT(FILTER(B4:B, B4:B<>""), "00000"), B4:B}, 2), 0)))

我用过

=ArrayFormula(VLOOKUP(D4:D8&text(E4:E8,"0000"),A4:A10&text(B4:B10,"0000"),1,true))

从 J4 开始

然后

=ArrayFormula(if(--left(J4:J8)=D4:D8,--right(J4:J8,4),""))

从 K4 开始。

需要进一步细化,但不对前一组的最大值做出任何假设。

编辑

所以在进一步工作之后它看起来像这样

=ArrayFormula(if(D4:D="",,
if(D4:D=
vlookup(D4:D&text(E4:E,"0000"),filter({A4:A&text(B4:B,"0000"),A4:A},A4:A<>""),2,true),
vlookup(D4:D&text(E4:E,"0000"),filter({A4:A&text(B4:B,"0000"),B4:B},A4:A<>""),2,true),"")))

实际上很像@player0 的解决方案。

我想你可以通过做一些像

这样的事情让它更通用一点
=text(B4,rept("0",ceiling(log10(max(B4:B)))))

假设这些都是正整数。


替代方法

我认为这是更好的方法。找出每组的起始行,以及该组中有多少行 r 小于或等于所需的 group/value 对。然后就是从组的第一行往前走r-1行,找到匹配的值:

=ArrayFormula(if(countifs(A4:A,D4:D,B4:B,"<="&E4:E)>0,
vlookup(
  vlookup(D4:D,{A4:A,row(A4:A)},2,false)+countifs(A4:A,D4:D,B4:B,"<="&E4:E)-1,{row(A4:A),B4:B},2,false),))

当然假设主数据是按组和值排序的——否则你将不得不使用 sort():

=ArrayFormula(if(countifs(A4:A,D4:D,B4:B,"<="&E4:E)>0,
vlookup(
  vlookup(D4:D,{sort(A4:A,A4:A,1,B4:B,1),row(A4:A)},2,false)+countifs(A4:A,D4:D,B4:B,"<="&E4:E)-1,{row(A4:A),SORT(B4:B,A4:A,1,B4:B,1)},2,false),))