Search code examples
jsonwhile-loopjq

Count elements whilst predicate is true


I have a collection of JSON objects like so:

{"id":"da1234563","message":"brown fox jump over a red log"}
{"id":"da1234564","message":"brown fox jump over a red log"}
{"id":"da1234565","message":"brown fox jump over a red log"}
{"id":"da1234566","message":"brown fox jump over a red log"}
{"id":"da1234567","message":"red fox jump over a brown log"}
{"id":"da1234568","message":"another random string"}
{"id":"da1234569","message":"brown fox jump over a red log"}

I'd like to use jq to iterate over these objects and return the number of brown fox's jumping UNTIL a match is not found.

The following jq gives me every line with brown fox including the last line:

jq -n 'inputs|select(.message|test("brown fox"))'

How do I exclude the matches after a mismatch and count the number of matches so that jq returns only 4?


Solution

  • For efficiency, it is best to avoid "slurping" the input, which as envisioned in the Q, can in this case can be done quite simply by using input (or inputs) and the -n command-line option.

    Using a stream-oriented counting function and the built-in while:

    def count(s): reduce s as $x (0; .+1);
    
    count(while (inputs | .message|test("brown fox"); true) )
    

    An alternative

    def count(s): reduce s as $x (0; .+1);
    
    def select_while(s; cond):
      label $out | s | if cond then . else break $out end;
    
    count( select_while(inputs; .message|test("brown fox") ) )