jq sorts KEY and VALUES in different way - how can I enumerate them in the same order? jq sorts KEY and VALUES in different way - how can I enumerate them in the same order? unix unix

jq sorts KEY and VALUES in different way - how can I enumerate them in the same order?


The problem stems from jq's possibly surprising default behavior:

  • keys enumerates the keys alphabetically sorted.
  • .[] enumerates the values based on the keys' input order[1]

In other words: If you use keys to extract an object's keys in one pass, and then .[] to extract its values in another, the corresponding output elements might not match.

jq v1.5 introduced the keys_unsorted/0 function, which enables a simple solution:

# Sample input with unordered keys.# Sorting the values results in the same order as sorting the keys,# so the output order of values below implies the key enumeration order that was applied.json='{ "c":3, "a":1, "b":2 }'

Print keys in input order, using keys_unsorted/0:

$ echo "$json" | jq -r 'keys_unsorted[]'cab

Print values in input order, which [] invariably does:

$ echo "$json" | jq -r '.[]'312

Caveat: Up to version v1.3, using .[] resulted in no guaranteed enumeration order (the underlying hash table's key sorting was used, which is an implementation detail); if you still must use v1.3, you can use the to_entries approach shown below.


[v1.3+] to_entries/0, as used in user2259432's helpful answer, also enumerates the properties in input order:

# Extract keys$ echo "$json" | jq -r 'to_entries | map(.key)[]'cab
# Extract values$ echo "$json" | jq -r 'to_entries | map(.value)[]'312

Caveat: Prior to v1.5, to_entries/0 output key-value pairs in sorted-by-key order.

However, since to_entries/0 can be used to enumerate both keys and values, it is still a viable solution for producing a stable enumeration order in parallel key/value extractions, even in pre-v1.5 versions.


[v1.3+] If, by contrast, you want to enumerate in sorted-by-key order:

Print keys in alphabetically sorted order, using keys/0:

$ echo "$json" | jq -r 'keys[]'abc

Print values by alphabetically sorted keys:

$ echo "$json" | jq -r 'keys[] as $k | .[$k]'123

A caveat re -S / --sort-keys:

This option only applies to whole objects, on output:

$ echo "$json" | jq -Sc '.'{"a":1,"b":2,"c":3}  # Sorted by key

It doesn't apply when you use an operator or function to access the internals of an object:

$ echo "$json" | jq -S '.[]' # !! -S doesn't apply, because [] always uses input order312

[1] Prior to v1.5, no particular order was guaranteed, resulting the same problem, however.


jq has an option to sort the keys. See http://stedolan.github.io/jq/manual/#Invokingjq

--sort-keys / -S:Output the fields of each object with the keys in sorted order.

However the current released version (1.3) of jq doesn't have this enhancement yet, you'll need to compile jq via latest code from it's master branch. See http://stedolan.github.io/jq/download/ , the "From source on Linux or OS X" section.

For a complete history and details of this feature, see issue #79 "Option or function to sort object members by name" https://github.com/stedolan/jq/issues/79


You can also

$ echo '{"a":0, "b":1}' | jq -c 'to_entries|map([.key, .value])|map(.[])'["a",0,"b",1]