ArrayFormula 其中 returns 倒数第二个匹配
ArrayFormula which returns the second last matching
我有一个 table 收集许多不同玩家的 总分 的每日读数。由于是手动采集,可能有的玩家每天会不止一次添加阅读量,也有可能一天甚至更长时间根本没有阅读量。
该结构是非常基本的 3 列(日期、玩家、总计)。
我正在寻找一个 ArrayFormula
可以自动将特定玩家的 每日得分 填入第 4 列。这可以通过一个公式来实现,该公式找到特定玩家的倒数第二个读数并将其从 last/current 读数中减去。
Date
Player
Total
Daily
17/10/2021
Player 001
1500
1500
17/10/2021
Player 007
700
700
19/10/2021
Player 003
700
700
19/10/2021
Player 005
100
100
19/10/2021
Player 004
1100
1100
19/10/2021
Player 006
300
300
19/10/2021
Player 002
900
900
20/10/2021
Player 006
900
600
20/10/2021
Player 006
1600
700
20/10/2021
Player 002
1100
200
20/10/2021
Player 005
600
500
20/10/2021
Player 009
200
200
21/10/2021
Player 001
1600
100
21/10/2021
Player 003
1000
300
我找到了一个非常有趣的解决方案,但由于它基于 INDIRECT
,因此无法与 ArrayFormula
一起使用:
https://infoinspired.com/google-docs/spreadsheet/find-the-last-matching-value-in-google-sheets/
我想到了一种不同的方法,使用 VLOOKUP
并将搜索范围限制为当前行上方的行,然后找到该范围内的最后一个匹配值(-实际上是第二个-最后 table),但我找不到适用于 ArrayFormula 的语法。
有什么想法吗?
我将提供一个暂定的解决方案,但要知道在无法查看一些实际数据和预期结果的情况下编写这样的公式总是很困难。
假设您的数据在 A2:C 中(headers 在 A1:C1 中)。在原本为空的 Col D 的 D2 中尝试以下公式:
=ArrayFormula(IF(A2:A="",,C2:C - (VLOOKUP(B2:B&(A2:A-1), SORT({ {"", 0}; {B2:B&A2:A, C2:C} }), 2, TRUE) * (VLOOKUP(B2:B&(A2:A-1), SORT({ {"", 0}; {B2:B&A2:A, B2:B} }), 2, TRUE) = B2:B))))
要找到每位玩家的 second-to-last 得分,VLOOKUP
会在包含 A 的 SORT
ed 虚拟范围内查找每一行的 player-and-“昨天”的串联.) {null, 0} 在 B 之上。) {每行的 player-and-date, score 的串联}.
因为SORT
,可以使用最后一个参数TRUE
,这意味着如果找不到player-and-“昨天”的精确匹配,最接近的之前的匹配将被返回。 * VLOOKUP(...)
是为了确保之前的匹配是同一个人(因为每个人最早日期之前的字母顺序条目将是其他人的 last 日期,除了按字母顺序排列的第一人称,谁将弹回 {null, 0})。
但是,如果您的 sheet 数据下方始终至少有一个空白行,您可以稍微简化一下:
=ArrayFormula(IF(A2:A="",,C2:C - (VLOOKUP(B2:B&(A2:A-1), SORT({B2:B&A2:A, C2:C}), 2, TRUE) * (VLOOKUP(B2:B&(A2:A-1), SORT({B2:B&A2:A, B2:B}), 2, TRUE) = B2:B))))
这是因为bounce-back对于第一个字母的人的第一次约会,会为所有空行查找{null, null},相当于{null, 0},都将SORT
ed 早于你所有的数据。所以我们不需要将它包含在虚拟阵列设置中。
如果结果不符合预期,请分享符合预期结果的最小真实数据集。
ADDENDUM(根据 OP 的附加评论):
如果一个玩家每天可以输入多个分数,您可以使用下面的公式版本。
如果您不确定,您的数据下方至少会有一个空白行:
=ArrayFormula(IF(A2:A="",,C2:C - (VLOOKUP(B2:B&TEXT(ROW(B2:B)-1,"0000"), SORT({ {"", 0}; {B2:B&TEXT(ROW(B2:B),"0000"), C2:C} }), 2, TRUE) * (VLOOKUP(B2:B&TEXT(ROW(B2:B)-1,"0000"), SORT({ {"", 0}; {B2:B&TEXT(ROW(B2:B),"0000"), B2:B} }), 2, TRUE) = B2:B))))
如果您确定您的数据下方始终至少有一个空白行:
=ArrayFormula(IF(A2:A="",,C2:C - (VLOOKUP(B2:B&TEXT(ROW(B2:B)-1,"0000"), SORT( {B2:B&TEXT(ROW(B2:B),"0000"), C2:C} ), 2, TRUE) * (VLOOKUP(B2:B&TEXT(ROW(B2:B)-1,"0000"), SORT( {B2:B&TEXT(ROW(B2:B),"0000"), B2:B} ), 2, TRUE) = B2:B))))
以上两个都用行号代替日期。然后,他们假设您的数据将始终按照实时发生的顺序输入,而不是随机输入(即,您不会在较晚日期的分数之后输入较早日期的分数)。如果您 将 可能输入乱序的东西,这也可以控制;但是我这里没有这样做。
试试这个:
=ARRAYFORMULA(
IF(
A2:A = "",,
C2:C
- IFNA(VLOOKUP(
MATCH(
B2:B,
UNIQUE(FILTER(B2:B, B2:B <> "")),
)
* 10^INT(LOG10(ROWS(A2:A)) + 1)
+ ROW(A2:A) - 1,
SORT(
{
SEQUENCE(COUNTUNIQUE(B2:B)) * {10^INT(LOG10(ROWS(A2:A)) + 1), 0};
FILTER(
{
MATCH(
B2:B,
UNIQUE(FILTER(B2:B, B2:B <> "")),
)
* 10^INT(LOG10(ROWS(A2:A)) + 1)
+ ROW(A2:A),
C2:C
},
A2:A <> ""
)
},
1, 1
),
2
))
)
)
我有一个 table 收集许多不同玩家的 总分 的每日读数。由于是手动采集,可能有的玩家每天会不止一次添加阅读量,也有可能一天甚至更长时间根本没有阅读量。 该结构是非常基本的 3 列(日期、玩家、总计)。
我正在寻找一个 ArrayFormula
可以自动将特定玩家的 每日得分 填入第 4 列。这可以通过一个公式来实现,该公式找到特定玩家的倒数第二个读数并将其从 last/current 读数中减去。
Date | Player | Total | Daily |
---|---|---|---|
17/10/2021 | Player 001 | 1500 | 1500 |
17/10/2021 | Player 007 | 700 | 700 |
19/10/2021 | Player 003 | 700 | 700 |
19/10/2021 | Player 005 | 100 | 100 |
19/10/2021 | Player 004 | 1100 | 1100 |
19/10/2021 | Player 006 | 300 | 300 |
19/10/2021 | Player 002 | 900 | 900 |
20/10/2021 | Player 006 | 900 | 600 |
20/10/2021 | Player 006 | 1600 | 700 |
20/10/2021 | Player 002 | 1100 | 200 |
20/10/2021 | Player 005 | 600 | 500 |
20/10/2021 | Player 009 | 200 | 200 |
21/10/2021 | Player 001 | 1600 | 100 |
21/10/2021 | Player 003 | 1000 | 300 |
我找到了一个非常有趣的解决方案,但由于它基于 INDIRECT
,因此无法与 ArrayFormula
一起使用:
https://infoinspired.com/google-docs/spreadsheet/find-the-last-matching-value-in-google-sheets/
我想到了一种不同的方法,使用 VLOOKUP
并将搜索范围限制为当前行上方的行,然后找到该范围内的最后一个匹配值(-实际上是第二个-最后 table),但我找不到适用于 ArrayFormula 的语法。
有什么想法吗?
我将提供一个暂定的解决方案,但要知道在无法查看一些实际数据和预期结果的情况下编写这样的公式总是很困难。
假设您的数据在 A2:C 中(headers 在 A1:C1 中)。在原本为空的 Col D 的 D2 中尝试以下公式:
=ArrayFormula(IF(A2:A="",,C2:C - (VLOOKUP(B2:B&(A2:A-1), SORT({ {"", 0}; {B2:B&A2:A, C2:C} }), 2, TRUE) * (VLOOKUP(B2:B&(A2:A-1), SORT({ {"", 0}; {B2:B&A2:A, B2:B} }), 2, TRUE) = B2:B))))
要找到每位玩家的 second-to-last 得分,VLOOKUP
会在包含 A 的 SORT
ed 虚拟范围内查找每一行的 player-and-“昨天”的串联.) {null, 0} 在 B 之上。) {每行的 player-and-date, score 的串联}.
因为SORT
,可以使用最后一个参数TRUE
,这意味着如果找不到player-and-“昨天”的精确匹配,最接近的之前的匹配将被返回。 * VLOOKUP(...)
是为了确保之前的匹配是同一个人(因为每个人最早日期之前的字母顺序条目将是其他人的 last 日期,除了按字母顺序排列的第一人称,谁将弹回 {null, 0})。
但是,如果您的 sheet 数据下方始终至少有一个空白行,您可以稍微简化一下:
=ArrayFormula(IF(A2:A="",,C2:C - (VLOOKUP(B2:B&(A2:A-1), SORT({B2:B&A2:A, C2:C}), 2, TRUE) * (VLOOKUP(B2:B&(A2:A-1), SORT({B2:B&A2:A, B2:B}), 2, TRUE) = B2:B))))
这是因为bounce-back对于第一个字母的人的第一次约会,会为所有空行查找{null, null},相当于{null, 0},都将SORT
ed 早于你所有的数据。所以我们不需要将它包含在虚拟阵列设置中。
如果结果不符合预期,请分享符合预期结果的最小真实数据集。
ADDENDUM(根据 OP 的附加评论):
如果一个玩家每天可以输入多个分数,您可以使用下面的公式版本。
如果您不确定,您的数据下方至少会有一个空白行:
=ArrayFormula(IF(A2:A="",,C2:C - (VLOOKUP(B2:B&TEXT(ROW(B2:B)-1,"0000"), SORT({ {"", 0}; {B2:B&TEXT(ROW(B2:B),"0000"), C2:C} }), 2, TRUE) * (VLOOKUP(B2:B&TEXT(ROW(B2:B)-1,"0000"), SORT({ {"", 0}; {B2:B&TEXT(ROW(B2:B),"0000"), B2:B} }), 2, TRUE) = B2:B))))
如果您确定您的数据下方始终至少有一个空白行:
=ArrayFormula(IF(A2:A="",,C2:C - (VLOOKUP(B2:B&TEXT(ROW(B2:B)-1,"0000"), SORT( {B2:B&TEXT(ROW(B2:B),"0000"), C2:C} ), 2, TRUE) * (VLOOKUP(B2:B&TEXT(ROW(B2:B)-1,"0000"), SORT( {B2:B&TEXT(ROW(B2:B),"0000"), B2:B} ), 2, TRUE) = B2:B))))
以上两个都用行号代替日期。然后,他们假设您的数据将始终按照实时发生的顺序输入,而不是随机输入(即,您不会在较晚日期的分数之后输入较早日期的分数)。如果您 将 可能输入乱序的东西,这也可以控制;但是我这里没有这样做。
试试这个:
=ARRAYFORMULA(
IF(
A2:A = "",,
C2:C
- IFNA(VLOOKUP(
MATCH(
B2:B,
UNIQUE(FILTER(B2:B, B2:B <> "")),
)
* 10^INT(LOG10(ROWS(A2:A)) + 1)
+ ROW(A2:A) - 1,
SORT(
{
SEQUENCE(COUNTUNIQUE(B2:B)) * {10^INT(LOG10(ROWS(A2:A)) + 1), 0};
FILTER(
{
MATCH(
B2:B,
UNIQUE(FILTER(B2:B, B2:B <> "")),
)
* 10^INT(LOG10(ROWS(A2:A)) + 1)
+ ROW(A2:A),
C2:C
},
A2:A <> ""
)
},
1, 1
),
2
))
)
)