问题描述
我有一个通过Zapier集成自动填充的Google表格。对于添加的每个新行,我需要评估一个给定的单元格(发件人名称)以在先前的行中找到托运人名称的最后一个实例,如果是,则为最后一个条目返回Row#。
我正在尝试创建一个仅在新行中查看名称并返回具有该名称的最新行号的公式。
Formula需要作为Array公式运行,以便数据自动填充到工作表中的每一行。
我尝试使用此公式,但是当重构为数组公式时,它不会为新行填充新值,而只会为所有行重复第一个值。
从J行:
=sumproduct(max(row(A$1:A3)*(F4=F$1:F3)))
我需要将此公式重构为自动填充其下所有单元格的Array公式。
我已经尝试过此版本,但是它不起作用:
=ArrayFormula(IF(ISBLANK($A2:$A),"",sumproduct(max(row(A$1:A3)*($F4:$F=F$1:F3))))
解决方法
脚本(可能是自定义功能?)会更好。
解决方案1
下面是可放入标题的公式(放入J1
中,删除下面的所有内容)。
它的工作速度比第二种解决方案快得多,并且没有N²大小限制。它也适用于空的托运人(& "♥"
用于空的托运人):只要A:A
列具有某些值,它将不会被忽略。
={
"Row of Last Entry";
ARRAYFORMULA(
IF(
A2:A = "","",VLOOKUP(
ROW(F2:F)
+ VLOOKUP(
F2:F & "♥",{
UNIQUE(F2:F & "♥"),SEQUENCE(ROWS(UNIQUE(F2:F)))
* POWER(10,INT(LOG10(ROWS(F:F))) + 1)
},2,0
),SORT(
{
ROW(F2:F) + 1
+ VLOOKUP(
F2:F & "♥",{
UNIQUE(F2:F & "♥"),SEQUENCE(ROWS(UNIQUE(F2:F)))
* POWER(10,INT(LOG10(ROWS(F:F))) + 1)
},0
),ROW(F2:F);
{
SEQUENCE(ROWS(UNIQUE(F2:F)))
* POWER(10,INT(LOG10(ROWS(F:F))) + 1),SEQUENCE(ROWS(UNIQUE(F2:F)),1,0)
}
},1
),1
)
)
)
}
工作原理的详细信息
- 对于每一行,我们使用
VLOOKUP
在已排序的虚拟范围内搜索特殊数字,以获取与当前条目匹配的前一个条目的行号。 - 行的特殊编号是这样构造的:我们获得唯一条目中当前条目的序列号,并将其附加到当前行号之后。
- 生成的特殊编号的右部分(行编号)必须在它们之间对齐。如果条目的序号为13,行号为1234,并且有100500行,则该序号必须为
13001234
。001234
是对齐的右侧部分。 - 对齐是通过将序列号乘以
(log10(total number of rows) + 1)
的幂乘以10,得出13000000
(来自上面的示例)。这种方法用于避免使用LEN
和TEXT
-使用数字比使用字符串更快。 - 第一列的虚拟范围特殊数字与第二列的原始行数字几乎相同。
- 几乎相同的特殊数字:它们只是增加了1,所以
VLOOKUP
将在与当前字符串对应的数字之前最多停止一步。 - 虚拟范围还具有一些特殊行(在排序之前在底部添加),其中所有
0
都是其特殊编号(第一列)的右侧,而0
是行号(第二列)。这样做是为了VLOOKUP
将在条目的第一次出现时找到它。 - 虚拟范围已排序,因此我们可以使用外部
is_sorted
的{{1}}参数设置为1:这将导致最后一次匹配小于或等于要查找的数字。 / li> -
VLOOKUP
将附加到条目,因此& "♥"
也将找到空条目。
解决方案2-速度慢且有限制
但是对于足够小的行数,此公式有效(放入VLOOKUP
中,删除下面的所有内容):
J1
但是有一个问题。公式中的虚拟范围的大小为N²,其中N是行数。对于当前的1253行,它可以工作。但是有一个限制,在此之后它将引发范围过大的错误。
这就是使用={
"Row of Last Entry";
ARRAYFORMULA(
REGEXEXTRACT(
TRANSPOSE(QUERY(TRANSPOSE(
IF(
(FILTER(ROW(F2:F),F2:F <> "") > TRANSPOSE(FILTER(ROW(F2:F),F2:F <> "")))
* (FILTER(F2:F,F2:F <> "") = TRANSPOSE(FILTER(F2:F,F2:F <> ""))),TRANSPOSE(FILTER(ROW(F2:F),F2:F <> "")),""
)
),ROWS(FILTER(F2:F,F2:F <> "")))),"(\d*)\s*$"
)
)
}
而不仅仅是FILTER(...)
的原因。
这里是获取您感兴趣的信息的一种非常简单的方法。(我认为。)我主要是在猜测您想要的东西,因为您的问题不是真正关于您想要的东西,而是关于如何得到您认为会帮助您获得想要的东西的东西。这是XY problem的示例。我试图根据经验来猜测您的实际追求。
This editable sheet仅包含3个公式。 2在原始数据表上,在一个名为“分析”的新标签中。
“原始数据”选项卡上的第一个公式使用MMULT和SPLIT函数的组合提取格式正确的时间戳,如下所示:
=ARRAYFORMulA({"Good Timestamp";IF(A2:A="",MMULT(N(IFERROR(SPLIT(A2:A,"T"))),{1;1}))})
第二个公式查找自该托运人的上一个时间戳以来的时间量。并从当前时间戳中减去它,从而为您提供时间戳之间的时间。但是,仅在时间少于200分钟时才执行此操作。如果超过200分钟,则假定对于该托运人而言,这是一次不同的班次。它看起来像这样,并结合使用LOOKUP()和SUBSTITUTE()来确保提取正确的时间戳。显然,您可以找到200并将其更改为更合适的值。
=ARRAYFORMULA({"Minutes/Order";IF(A2:A="",IF(IFERROR((G2:G-1*SUBSTITUTE(LOOKUP(F2:F&G2:G-0.00001,SORT(F2:F&G2:G)),F2:F,""))*24*60)>200,IFERROR((G2:G-1*SUBSTITUTE(LOOKUP(F2:F&G2:G-0.00001,""))*(24*60))))})
第三个公式,在名为“分析”的选项卡上,使用查询来显示每个订单的平均分钟数和每个托运人正在处理的每小时订单数。看起来像这样:
=QUERY({'Sample Data'!F:I},"Select Col1,AVG(Col3),COUNT(Col3)/(SUM(Col3)/60) where Col3 is not null group by Col1 label COUNT(Col3)/(SUM(Col3)/60)'Orders/ hour',AVG(Col3)'Minutes/ Order'")
希望我已经正确地猜到了您的实际目标。始终尽力解释它们是什么,而不是仅索取一小部分您认为会帮助您获得答案的东西。您最终可能会使过程变得过于复杂,而没有意识到。