From 1bebd23aad8bca3e7626ecc2543f7033733d4053 Mon Sep 17 00:00:00 2001 From: itchyny Date: Sun, 6 Oct 2024 08:25:38 +0900 Subject: [PATCH] add skip/2 as the counterpart to limit/2 (#3181) I also changed the behavior of limit/2 with negative count to emit an error, like nth/2 does. Also, I redefined nth/2 using skip/2 to minimize the impact of growth of builtin filters. --- docs/content/manual/dev/manual.yml | 16 +++++++++++++--- jq.1.prebuilt | 23 +++++++++++++++++++---- src/builtin.jq | 14 +++++++++----- tests/jq.test | 24 ++++++++++++++++++++++++ tests/man.test | 6 +++++- 5 files changed, 70 insertions(+), 13 deletions(-) diff --git a/docs/content/manual/dev/manual.yml b/docs/content/manual/dev/manual.yml index c98b3ca259..60debde5e5 100644 --- a/docs/content/manual/dev/manual.yml +++ b/docs/content/manual/dev/manual.yml @@ -3037,16 +3037,26 @@ sections: input: '[1,2,3]' output: ['false'] - - title: "`limit(n; exp)`" + - title: "`limit(n; expr)`" body: | - The `limit` function extracts up to `n` outputs from `exp`. + The `limit` function extracts up to `n` outputs from `expr`. examples: - - program: '[limit(3;.[])]' + - program: '[limit(3; .[])]' input: '[0,1,2,3,4,5,6,7,8,9]' output: ['[0,1,2]'] + - title: "`skip(n; expr)`" + body: | + + The `skip` function skips the first `n` outputs from `expr`. + + examples: + - program: '[skip(3; .[])]' + input: '[0,1,2,3,4,5,6,7,8,9]' + output: ['[3,4,5,6,7,8,9]'] + - title: "`first(expr)`, `last(expr)`, `nth(n; expr)`" body: | diff --git a/jq.1.prebuilt b/jq.1.prebuilt index 1d1424f68d..d3e44cfbd1 100644 --- a/jq.1.prebuilt +++ b/jq.1.prebuilt @@ -1,5 +1,5 @@ . -.TH "JQ" "1" "August 2024" "" "" +.TH "JQ" "1" "September 2024" "" "" . .SH "NAME" \fBjq\fR \- Command\-line JSON processor @@ -3435,14 +3435,14 @@ jq \'isempty(\.[])\' . .IP "" 0 . -.SS "limit(n; exp)" -The \fBlimit\fR function extracts up to \fBn\fR outputs from \fBexp\fR\. +.SS "limit(n; expr)" +The \fBlimit\fR function extracts up to \fBn\fR outputs from \fBexpr\fR\. . .IP "" 4 . .nf -jq \'[limit(3;\.[])]\' +jq \'[limit(3; \.[])]\' [0,1,2,3,4,5,6,7,8,9] => [0,1,2] . @@ -3450,6 +3450,21 @@ jq \'[limit(3;\.[])]\' . .IP "" 0 . +.SS "skip(n; expr)" +The \fBskip\fR function skips the first \fBn\fR outputs from \fBexpr\fR\. +. +.IP "" 4 +. +.nf + +jq \'[skip(3; \.[])]\' + [0,1,2,3,4,5,6,7,8,9] +=> [3,4,5,6,7,8,9] +. +.fi +. +.IP "" 0 +. .SS "first(expr), last(expr), nth(n; expr)" The \fBfirst(expr)\fR and \fBlast(expr)\fR functions extract the first and last values from \fBexpr\fR, respectively\. . diff --git a/src/builtin.jq b/src/builtin.jq index aa33cd4b75..0d1d6774ab 100644 --- a/src/builtin.jq +++ b/src/builtin.jq @@ -149,10 +149,14 @@ def until(cond; next): def _until: if cond then . else (next|_until) end; _until; -def limit($n; exp): - if $n > 0 then label $out | foreach exp as $item ($n; .-1; $item, if . <= 0 then break $out else empty end) - elif $n == 0 then empty - else exp end; +def limit($n; expr): + if $n > 0 then label $out | foreach expr as $item ($n; . - 1; $item, if . <= 0 then break $out else empty end) + elif $n == 0 then empty + else error("limit doesn't support negative count") end; +def skip($n; expr): + if $n > 0 then foreach expr as $item ($n; . - 1; if . < 0 then $item else empty end) + elif $n == 0 then expr + else error("skip doesn't support negative count") end; # range/3, with a `by` expression argument def range($init; $upto; $by): if $by > 0 then $init|while(. < $upto; . + $by) @@ -169,7 +173,7 @@ def any: any(.[]; .); def last(g): reduce g as $item (null; $item); def nth($n; g): if $n < 0 then error("nth doesn't support negative indices") - else label $out | foreach g as $item ($n + 1; . - 1; if . <= 0 then $item, break $out else empty end) end; + else first(skip($n; g)) end; def first: .[0]; def last: .[-1]; def nth($n): .[$n]; diff --git a/tests/jq.test b/tests/jq.test index 446ee36952..83d817d4e5 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -334,6 +334,30 @@ null "badness" [1] +try limit(-1; error) catch . +null +"limit doesn't support negative count" + +[skip(3; .[])] +[1,2,3,4,5,6,7,8,9] +[4,5,6,7,8,9] + +[skip(0,2,3,4; .[])] +[1,2,3] +[1,2,3,3] + +[skip(3; .[])] +[] +[] + +try skip(-1; error) catch . +null +"skip doesn't support negative count" + +nth(1; 0,1,error("foo")) +null +1 + [first(range(.)), last(range(.))] 10 [0,9] diff --git a/tests/man.test b/tests/man.test index 6c5eba390a..5529e011ef 100644 --- a/tests/man.test +++ b/tests/man.test @@ -873,10 +873,14 @@ isempty(.[]) [1,2,3] false -[limit(3;.[])] +[limit(3; .[])] [0,1,2,3,4,5,6,7,8,9] [0,1,2] +[skip(3; .[])] +[0,1,2,3,4,5,6,7,8,9] +[3,4,5,6,7,8,9] + [first(range(.)), last(range(.)), nth(./2; range(.))] 10 [0,9,5]