Reputation: 10833
I have a series of [timestamp, count]
pairs in an array and a want to compute the cumulative sum at each timestamp using jq
. How could I do that?
Here a sample data set:
[
[1431047957699, 1],
[1431047958269, 1],
[1431047958901, 1],
[1431047959147, -1],
[1431047960164, 1]
]
And the expected result:
[1431047957699, 1],
[1431047958269, 2],
[1431047958901, 3],
[1431047959147, 2],
[1431047960164, 3]
Is it possible to do this with jq
?
Upvotes: 2
Views: 2067
Reputation: 116900
The following is quite general (e.g. it can be used with an array of objects):
def accumulate(f):
reduce .[1:][] as $row
([.[0]];
. as $x
| $x + [ $row | (f = ($x | .[length-1] | f) + ($row|f) ) ] );
accumulate(.[1])
If you are using a sufficiently recent version of jq, then "$x | .[length-1]" can be simplified to "$x[-1]".
If your jq has foreach, then the following variant can be used. It would be particularly appropriate if a stream of values rather than array is wanted.
def accumulates(f):
foreach .[] as $row
(0;
. + ($row | f) ;
. as $x | $row | (f = $x));
Usage:
For a stream: accumulates(.[0])
For an array: [accumulates(.[0])
Upvotes: 4
Reputation: 134521
Take a functional approach to this and create an update function that will create the updated values with the cumulative sum.
def accumulate(acc):
select(length > 0) |
(.[0][1] + acc) as $next |
(.[0] | .[1] = $next), (.[1:] | accumulate($next))
;
[accumulate(0)]
Here, we break the array into "head" and "tail" updating the head with the current sum and recursively update the tail. The results are placed back into a new array.
Upvotes: 2