Apply TCO to recurse/1, add recurse/2; tweak docs

Signed-off-by: Nicolas Williams <nico@cryptonector.com>
This commit is contained in:
pkoppstein authored and Nicolas Williams committed 2014-08-04 21:11:01 -05:00
1 parent a2f99d43c3
commit f8fed0f0bc
2 files changed
+35 -7

No files matched your search

+5 -1
View File
@@ -928,9 +928,13 @@ static const char* const jq_builtins[] = {
"def del(f): delpaths([path(f)]);", "def del(f): delpaths([path(f)]);",
"def _assign(paths; value): value as $v | reduce path(paths) as $p (.; setpath($p; $v));", "def _assign(paths; value): value as $v | reduce path(paths) as $p (.; setpath($p; $v));",
"def _modify(paths; update): reduce path(paths) as $p (.; setpath($p; getpath($p) | update));", "def _modify(paths; update): reduce path(paths) as $p (.; setpath($p; getpath($p) | update));",
"def recurse(f): ., (f | select(. != null) | recurse(f));",
// recurse
"def recurse(f): def r: ., (f | select(. != null) | r); r;",
"def recurse(f; cond): def r: ., (f | select(cond) | r); r;",
"def recurse: recurse(.[]?);", "def recurse: recurse(.[]?);",
"def recurse_down: recurse;", "def recurse_down: recurse;",
"def to_entries: [keys[] as $k | {key: $k, value: .[$k]}];", "def to_entries: [keys[] as $k | {key: $k, value: .[$k]}];",
"def from_entries: map({(.key): .value}) | add | .//={};", "def from_entries: map({(.key): .value}) | add | .//={};",
"def with_entries(f): to_entries | map(f) | from_entries;", "def with_entries(f): to_entries | map(f) | from_entries;",
+30 -6
View File
@@ -22,7 +22,7 @@ body: |
combine two filters, like addition, generally feed the same input to combine two filters, like addition, generally feed the same input to
both and combine the results. So, you can implement an averaging both and combine the results. So, you can implement an averaging
filter as `add / length` - feeding the input array both to the `add` filter as `add / length` - feeding the input array both to the `add`
filter and the `length` filter and dividing the results. filter and the `length` filter and then performing the division.
But that's getting ahead of ourselves. :) Let's start with something But that's getting ahead of ourselves. :) Let's start with something
simpler: simpler:
@@ -40,14 +40,16 @@ manpage_intro: |
running the command `jq 'map(.price) | add'` will take an array of running the command `jq 'map(.price) | add'` will take an array of
JSON objects as input and return the sum of their "price" fields. JSON objects as input and return the sum of their "price" fields.
By default, `jq` reads a stream of JSON objects (whitespace `jq` can accept text input as well, but by default, `jq` reads a
separated) from `stdin`. One or more <files> may be specified, in stream of JSON entities (including numbers and other literals) from
`stdin`. Whitespace is only needed to separate entities such as 1
and 2, and true and false. One or more <files> may be specified, in
which case `jq` will read input from those instead. which case `jq` will read input from those instead.
The <options> are described in the [INVOKING JQ] section, they The <options> are described in the [INVOKING JQ] section; they
mostly concern input and output formatting. The <filter> is written mostly concern input and output formatting. The <filter> is written
in the jq language and specifies how to transform the input in the jq language and specifies how to transform the input
document. file or document.
## FILTERS ## FILTERS
@@ -1250,7 +1252,7 @@ sections:
output: ['[1,2,4,8,16,32,64]'] output: ['[1,2,4,8,16,32,64]']
- title: "`recurse(f)`, `recurse`, `recurse_down`" - title: "`recurse(f)`, `recurse`, `recurse(f; condition), `recurse_down`"
body: | body: |
The `recurse(f)` function allows you to search through a The `recurse(f)` function allows you to search through a
@@ -1275,10 +1277,24 @@ sections:
When called without an argument, `recurse` is equivalent to When called without an argument, `recurse` is equivalent to
`recurse(.[]?)`. `recurse(.[]?)`.
`recurse(f) is identical to `recurse(f; . != null)` and can be
used without concerns about recursion depth.
`recurse(f; condition)` is a generator which begins by
emitting . and then emits in turn .|f, .|f|f, .|f|f|f, ... so long
as the computed value satisfies the condition. For example,
to generate all the integers, at least in principle, one
could write `recurse(.+1; true)`.
For legacy reasons, `recurse_down` exists as an alias to For legacy reasons, `recurse_down` exists as an alias to
calling `recurse` without arguments. This alias is considered calling `recurse` without arguments. This alias is considered
*deprecated* and will be removed in the next major release. *deprecated* and will be removed in the next major release.
These `recurse` filters are all written to take advantage of
jq's optimizations of certain cases of tail recursion. In
particular, there is no memory overhead due to the
recursion.
examples: examples:
- program: 'recurse(.foo[])' - program: 'recurse(.foo[])'
input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}' input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}'
@@ -1287,6 +1303,7 @@ sections:
- '{"foo":[]}' - '{"foo":[]}'
- '{"foo":[{"foo":[]}]}' - '{"foo":[{"foo":[]}]}'
- '{"foo":[]}' - '{"foo":[]}'
- program: 'recurse' - program: 'recurse'
input: '{"a":0,"b":[1]}' input: '{"a":0,"b":[1]}'
output: output:
@@ -1294,6 +1311,13 @@ sections:
- '[1]' - '[1]'
- '1' - '1'
- program: 'recurse(. * .; . < 20)'
input: 2
output:
- 2
- 4
- 16
- title: "`..`" - title: "`..`"
body: | body: |