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

China☆狼群 提交于 2021-01-21 04:39:27

问题


I get REST output in JSON format using curl command as below

Getting KEY names alone using:

curl http://test.te:8080/testApp/app/version | jq '.version' | jq '. | keys'

OUTPUT:

"Archiver-Version",
"Build-Id",
"Build-Jdk",
"Build-Number",
"Build-Tag",
"Built-By"

Getting VALUES alone using:

curl http://test.te.com:8080/testApp/app/version | jq '.version' | jq '.[]'

OUTPUT (Note how the order of values doesn't correspond to the order of key names; e.g., the first value, "user@test.com", is the value for key "Built-By", not, as I would expect, for the first key, "Archiver-Version"):

"user@test.com"
"1634d38"
"sandbox"
"02-03-2014-13:41"
"testApp"

I am trying to assign the KEYS and VALUES to separate arrays, so that I can iterate over them and display them in table format.

But these two commands are sorted in different way, I cannot assign the values and keys directly.

Is there anyway to change the sorting of KEYS and VALUES so that both are same?


回答1:


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




回答2:


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[]'
c
a
b

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

$ echo "$json" | jq -r '.[]'
3
1
2

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)[]'
c
a
b
# Extract values
$ echo "$json" | jq -r 'to_entries | map(.value)[]'
3
1
2

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[]'
a
b
c

Print values by alphabetically sorted keys:

$ echo "$json" | jq -r 'keys[] as $k | .[$k]'
1
2
3

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 order
3
1
2

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




回答3:


You can also

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


来源:https://stackoverflow.com/questions/23120359/jq-sorts-key-and-values-in-different-way-how-can-i-enumerate-them-in-the-same

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!