I have a JSON array that looks like:
["a","b","c"]
And I have a bash variable which is list of array indices that I would like to subset to
ix="0,2"
I would like to use jq
to subset to those indices, yielding the following array:
["a", "c"]
So far I've been able to parse $ix
into an array:
echo '["a","b","c"]' | jq --arg ix $ix '$ix | split(",") | map(tonumber)'
But when I try to use this array of indices to subset ["a","b","c"]
, I have problems (None of the following work):
echo '["a","b","c"]' | jq --arg ix $ix '. | $ix | split(",") | map(tonumber)'
echo '["a","b","c"]' | jq --arg ix $ix '. | ($ix | split(",") | map(tonumber))'
echo '["a","b","c"]' | jq --arg ix $ix '. | [$ix | split(",") | map(tonumber)]'
echo '["a","b","c"]' | jq --arg ix $ix '. | .[$ix | split(",") | map(tonumber)]'
CodePudding user response:
I'd do
jq --arg ix "$ix" '
($ix | split(",") | map(tonumber)) as [$a, $b]
| .[$a:$b 1]
'
The 1
is needed because the array slice operation .[from;to]
is from (inclusive) and to (exclusive)
The variable-assignment expression ... | exp as $var | ...
uses the input value in the expression, sets the variable, then passes the original input as its output.
Another way to do this: split the ix in bash, and pass the values as positional arguments:
IFS=, read -ra ixs <<< "$ix"
echo '["a","b","c"]' \
| jq --jsonargs '.[$ARGS.positional[0]:$ARGS.positional[1] 1]' "${ixs[@]}"
So, you have a huge array and a large list of indices to extract? Then perhaps:
. as $some_huge_array |
reduce ($ix | split(",") | map(tonumber))[] as $i ([]; . [$some_huge_array[$i]])
Rolling up some of these ideas:
ix="0,3,4"
jq --argjson ixs "[$ix]" '. as $a | reduce $ixs[] as $i ([]; . [$a[$i]])' <<END_INPUT
[1, 2, 3, 4, 5, 6, 7]
END_INPUT
[
1,
4,
5
]
And as @oguzismail points out, reduce
is not needed here
jq --argjson ixs "[$ix]" '[.[$ixs[]]]'
$ixs
is an array$ixs[]
is a stream of values.[ $ixs[] ]
will output the values of the input array for each value of $ixs, as a stream of values- this is an implicit iteration
[ .[$ixs[]] ]
collects the previous stream into an array.
CodePudding user response:
$ cat test.json ["a", "b", "c", "d", "e" ]
$ ix="0,2"
$ jq --arg ix "$ix" '($ix | split(",") | map(tonumber)) as [$a, $b] | .[$a:$b 1]' test.json
[ "a", "b", "c" ]
$ jq --arg ix "$ix" '($ix | split(",") | map(tonumber)) as [$a, $b] | .[$a,$b 1]' test.json
"a"
"d"
Note how the output differs between [$a:$b 1] and [$a,$b 1].
[$a:$b 1] is array slicing which generates a sub-array whereas [$a,$b 1] selects two individual elements of the original array.