How to compare values in different objects jq

Viewed 588

JSON :

{"blockHistory":[10, 12, 14, 17],
"hashrateHistory":[
{"hr":1,"time":9},
{"hr":2,"time":10},
{"hr":3,"time":11},
{"hr":4,"time":12},
{"hr":5,"time":13},
{"hr":6,"time":14},
{"hr":7,"time":15}
]

I want to get hr for every value from blockHistory where time from hashrateHistory is the biggest time <= blockHistory value.

This is what i have. I don't know how to get the lastHR

 [{lastHr: .hashrateHistory[].hr, time: .blockHistory[]}] | sort_by(.time)

result i want:

[
  {
    "lastHr": 2,
    "time": 10
  },
  {
    "lastHr": 4,
    "time": 12
  },
  {
    "lastHr": 6,
    "time": 14
  },
  {
    "lastHr": 7,
    "time": 17
  }

]

3 Answers
(.hashrateHistory | sort_by(.time)) as $hashrate
| .blockHistory | map(
    . as $max_time
    | $hashrate
    | map(select(.time <= $max_time))[-1]
    | {lastHr: .hr, time: $max_time}
)

For each element of block, iterate over sorted/saved hashrate. Select only the last matching element and create an object within the block map.

Here's another approach which uses group_by after building an intermediate result

  .blockHistory as $b
| [ .hashrateHistory[] | .group = [ $b[] < .time ] ] 
| group_by(.group) 
| map(max_by(.time) | del(.group)) 
| sort_by(.time)

Based on your original attempt this includes a final sort_by but it might not be necessary.

Try it online!

Here's a solution oriented towards time-efficiency on the assumption that the .blockHistory array is sufficiently large and "interesting" to offset the up-front investment in the construction of a dictionary ($dict) and the sorting of the .hashrateHistory array by .time.

The case of an exact match is handled using a dictionary ($dict), and the other case is handled using the built-in function bsearch for conducting a binary search:

.hashrateHistory as $hashrateHistory
| INDEX($hashrateHistory[]; .time) as $dict
| ($hashrateHistory | sort_by(.time) ) as $sorted
| ($sorted | map(.time)) as $sorted_time
| ($sorted | map(.hr)) as $sorted_hr
| .blockHistory
| map( . as $t
       | $dict[$t|tostring]
       | if . then {lastHr: .hr, time }
         else (-2 - ($sorted_time | bsearch($t))) as $i
         | {lastHr: $sorted_hr[$i], time: $t}
         end )

Related