jq 中的累计和

Cumulative sum in jq

我在数组中有一系列 [timestamp, count] 对,我想使用 jq 计算每个时间戳的累积和。我该怎么做?

这里是一个示例数据集:

[
  [1431047957699, 1],
  [1431047958269, 1],
  [1431047958901, 1],
  [1431047959147, -1],
  [1431047960164, 1]
]

预期结果:

[1431047957699, 1],
[1431047958269, 2],
[1431047958901, 3],
[1431047959147, 2],
[1431047960164, 3]

是否可以用 jq 做到这一点?

对此采用函数式方法并创建一个更新函数,该函数将使用累积总和创建更新值。

def accumulate(acc):
    select(length > 0) |
    (.[0][1] + acc) as $next |
    (.[0] | .[1] = $next), (.[1:] | accumulate($next))
    ;
[accumulate(0)]

在这里,我们将数组分成 "head" 和 "tail" 用当前总和更新头部并递归更新尾部。结果被放回一个新数组中。

以下是非常通用的(例如,它可以与对象数组一起使用):

def accumulate(f):
  reduce .[1:][] as $row
    ([.[0]];
     . as $x
     | $x + [ $row | (f = ($x | .[length-1] | f) + ($row|f)  ) ] );

accumulate(.[1])

如果您使用的是足够新的 jq 版本,那么“$x | .[length-1]”可以简化为“$x[-1]”。

使用foreach的解决方案

如果你的jq有foreach,那么可以使用下面的变体。如果需要值流而不是数组,这将特别合适。

def accumulates(f):
  foreach .[] as $row
    (0;
     . + ($row | f) ;
     . as $x | $row | (f = $x));

用法:

对于流:accumulates(.[0])

对于数组:[accumulates(.[0])