Hi,
what is the correct way to test for the type of a value?
Example: I only want to get arrays or objects and unwrap the contained values. If I don't filter out scalars jq gives an error:
% echo '[1, 2] 1' | jq '.[]'
1
2
jq: error: Cannot iterate over number
Now I test for arrays and objects "hijacking" the >= operator:
% echo '[1, 2] 1' | jq 'select(. >= []) | .[]'
1
2
Is there a better way of doing this?
And the general question is: How to test for
Regards,
Tilo
Thanks, i was looking for that! One hack to test for strings is:
echo '[1111] [] {"x":"y"} {} "z" 2222 true false null' | jq 'select(.==tostring)'
"z"
Based on your test for "object or array", just discovered a test for objects only:
echo '[1111] [] {"x":"y"} {} "z" 2222 true false null' | jq 'select(.>={})'
{
"x": "y"
}
{}
Can combine to test for arrays:
echo '[1111] [] {"x":"y"} {} "z" 2222 true false null' | jq 'select(.>=[] and .<{})'
[
1111
]
[]
Finally, can test for number by combining "not an object or array", string test and exhaustive explicit tests for not true/false/null:
echo '[1111] [] {"x":"y"} {} "z" 2222 true false null' |
jq 'select(.<[] and .!=tostring and .!=true and .!=false and .!=null)'
2222
Is there a shorter way?
While not as ingenious as @13ren's solution, you can also use the type function :)
$ echo '[true, null, 42, "hello", []]' | ./jq 'map(type)'
["boolean","null","number","string","array"]
On Wed, 23 Jan 2013 12:29:04 +0100, Stephen Dolan
[email protected] wrote:
While not as ingenious as @13ren's solution, you can also use the
type
function :)$ echo '[true, null, 42, "hello", []]' | ./jq 'map(type)' ["boolean","null","number","string","array"]
Great! Exactly what I was looking for.
I did search http://stedolan.github.com/jq/manual for such a function but
didn't find anything.
This function is probably useful for others too.
Regards,
This is great! It enables recurse(filter) to traverse arbitrary json (i.e. without an explicit field holding child values, unlike the reddit json in #37 which inspired it).
echo '[true, null, 42, "hello", []]' | jq 'recurse(.[])'
[
true,
null,
42,
"hello",
[]
]
true
jq: error: Cannot iterate over boolean
42
jq: error: Cannot iterate over number
"hello"
jq: error: Cannot iterate over string
[]
echo '[true, null, 42, "hello", []]' | jq 'recurse(select(type|.=="array"or.=="object") | .[])'
[
true,
null,
42,
"hello",
[]
]
true
42
"hello"
[]
NB: recurse omits nulls (due to its definition), and Tilo's sweet hack recurse( select(.>=[]) | .[] ) is shorter.
Would it make sense to include something like the above, as a builtin traverse(filter)? It seems an important special-case of recursion for JSON.
Aside: recurse can (of course) do general recursion e.g.
jq -n '0 | recurse( .+1|select(.<3) )'
0
1
2
Sorry, getting carried away here, but we can define a for-loop function, with optional step:
def for(args): args as $a| ($a[2] // 1) as $step| $a[0] | recurse( .+$step| select(.<$a[1]) );
for([0,4,2])
0
2
for([0,4])
0
1
2
3
Most helpful comment
While not as ingenious as @13ren's solution, you can also use the
typefunction :)