Home > Enterprise >  Subset json based on string list of indices using jq
Subset json based on string list of indices using jq

Time:09-10

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.

  • Related