文章

Google 表格公式 - 时间错位

本文介绍一个情景以及解决方案

Google 表格公式 - 时间错位

情景

假设有这么一个情景,

 ABC
1开始时间结束时间事件
207:0008:00 
308:0009:00 
409:0010:00 
510:0011:00 

我们要记录一下每天的日志,从几点到几点做了什么事。但是我们每次填写记录的时候,总是要先把上一个时间段的结束时间填到新行的开始时间上,再写上当前时间段的结束时间,比较繁琐。其实当前时间段的开始时间与上一时间段的结束时间总是一致的,也就是说,A3 等于 B2A4 等于 B3,以此类推。

所以每次我们新增时间段的时候,只有 B 列的值是有意义的,A 列的值可以通过 B 列的值计算出来,并不需要我们自己填。

那么怎么计算呢?

思路

我们还是考虑映射关系,对于 A2:AB2:B 两个范围,用索引来表示值之间的映射的话,就是这样:

  • 1 -> NA
  • 2 -> 1
  • 3 -> 2
  • 4 -> 3
  • 5 -> 4
  • ……

解释来说,就是 A2 没有映射,A3(索引 2)映射 B2(索引 1)的值,A4(索引 3)映射 B3(索引 2)的值,以此类推。

此映射及其简单,就是 IF(a=1, "", a-1)

所以思路就是,先生成一个从 1 开始,长度为 A2:A 范围长度,间隔为 1 的索引序列,对该序列进行映射,然后用映射后的索引定位到 B2:B 范围的值,就完成了。

实现

先将样表修改如下,D2 处的公式为 =ROWS(A2:A),用于计算 A2:A 的行数,也就是序列的长度,

 ABCD
1开始时间结束时间事件 
2 07:00 6
3 08:00  
4 09:00  
5 10:00  
6 11:00  
7    

A2 处输入公式 =SEQUENCE(D2, 1, 1, 1)

 ABCD
1开始时间结束时间事件 
2107:00 6
3208:00  
4309:00  
5410:00  
6511:00  
76   

然后使用映射,将 A2 公式改为 =MAP(SEQUENCE(D2, 1, 1, 1), LAMBDA(a, IF(a=1, "", a-1)))

 ABCD
1开始时间结束时间事件 
2 07:00 6
3108:00  
4209:00  
5310:00  
6411:00  
75   

使用新索引定位 B2:B 的值,将 A2 的公式改为

=MAP(SEQUENCE(D2, 1, 1, 1), LAMBDA(a, IF(a=1, "", INDEX(B2:B, a-1, 1))))

 ABCD
1开始时间结束时间事件 
2 07:00 6
307:0008:00  
408:0009:00  
509:0010:00  
610:0011:00  
711:00   

基本算完成了!但是还有一点小瑕疵就是 A 列最后留了一个小尾巴。其实这个也好解决,我们只需要判断一下 B 列每一行的值是不是空,如果是空,就不进行映射了。

A2 的公式改为

=MAP(SEQUENCE(D2,1,1,1), B2:B, LAMBDA(a,b, IF(a=1,"", IF(b="","", INDEX(B2:B,a-1,1)))))

 ABCD
1开始时间结束时间事件 
2 07:00 6
307:0008:00  
408:0009:00  
509:0010:00  
610:0011:00  
7    

最后将第 2 行隐藏即可,因为该行只是一个辅助行。

反转时间

在这里其实 D2 处的公式显得有些多余,完全可以将它合并到 A2 的公式中。但是在另一种情况下,预先计算行数就很有必要了。这种情况就是时间段反转。

因为记录日志是一个会频繁增加新行的操作,如果日志多了,我们需要不断地滚动鼠标滑轮才能找到最后一条日志(也就是上一条日志),而最开始的一些日志我们基本也不会去看它们了,它们却一直待在表格的最开头,这很没必要。

所以如果在记录日志时是从下往上增加新行记录的,旧的日志会逐渐往表格后排,而我们每次都在表格开头填加新记录,不需要滚动鼠标滑轮。这很方便,但是自动填写上一时间段的结束时间的公式就会发生变化了。

不过变化也不大,就是把映射公式中的 a-1 改为 a+1,同时 IF 不再判断 a=1 而是判断 a=ROWS(A2:A)。因为这个判断在 IF 中,也就是说每次映射都会判断一遍,也都会计算一遍 ROWS(A2:A) 的值,这样比较浪费资源,因为这个行数总是固定的。于是我们就可以将它预先计算出来,并存在某处,然后在公式里直接引用值就可以了,不需要每次映射都计算一遍。

A2 的公式改为

=MAP(SEQUENCE(D2,1,1,1), B2:B, LAMBDA(a,b, IF(a=D2,"",IF(b="","",INDEX(B2:B,a+1,1)))))

 ABCD
1开始时间结束时间事件 
2   6
309:0010:00  
408:0009:00  
507:0008:00  
606:0007:00  
7 06:00  

乌拉!

本文由作者按照 CC BY 4.0 进行授权