divedivedive
divedivedive

Reputation: 21

JQ Sorting Issue with Decimal Values?

I have following test data and am trying to jq sort in descending order by the highest weight, but having trouble with these decimal points, which the sort seems to ignore?

[
  {
    "name": "train",
    "amount": "4",
    "weight": "89129.70000000"
  },
  {
  "name": "plane",
  "amount": "200",
  "weight": "819002.68900000"
  },
  {
  "name": "car",
  "amount": "27",
  "weight": "527561695272.42000000"
  },
  {
  "name": "bike",
  "amount": "14",
  "weight": "9914795.00000000"
  },
  {
  "name": "truck",
  "amount": "92",
  "weight": "999147.00000000"
  }
]
jq -r 'map(select(.weight)) | sort_by(.weight)[] | [.name,.weight]' 

will output it incorrectly, it seems to ignore the decimal point eg.

[
  "car",
  "527561695272.42000000"
]
[
  "plane",
  "819002.68900000"
]
[
  "train",
  "89129.70000000"
]
[
  "bike",
  "9914795.00000000"
]
[
  "truck",
  "999147.00000000"
]

i've tried a few things and have managed to sort it via:

jq '[.[].weight] | sort_by( split(".") | map(tonumber) ) | reverse' 

which will sort output correctly:

[
  "527561695272.42000000",
  "9914795.00000000",
  "999147.00000000",
  "819002.68900000",
  "89129.70000000"
]

Think its because all outputs come in strings, and so need to use the tonumber function. However, from what I'm doing there, I'm not sure how to get jq to output the full objects, or other things like .name as in the first example. keep getting errors, seem to have put myself into a corner.

Ideally I just want the full output the objects but correctly sorted descending by weight, i.e. the full data, just sorted.

Upvotes: 1

Views: 438

Answers (1)

Introduction

Let's consider the following versions as the current versions:

  • jq: 1.6.

Number representation: Recommendation

but having trouble with these decimal points, which the sort seems to ignore?

Please, note that for some reason to represent numbers you are using string values instead of numeric values.
For example:

"weight": "89129.70000000"

Please, note that the number itself is in double quotes: this makes it a string value.

I would like to recommend you to correct the input data, so that numbers are represented by numeric values.
For example:

"weight": 89129.7

Solution

Please, consider using the sort_by() function with the appropriate path expression.

jq 1.6 Manual:

sort_by(foo) compares two elements by comparing the result of foo on each element.

When numbers are represented by string values

Since weight values are represented by string values (i.e. without taking into account the recommendation), it is necessary to perform the tonumber conversion to sort them as numeric values.

jq -r 'sort_by(.weight | tonumber) | reverse' input.json

Output

[
  {
    "name": "car",
    "amount": "27",
    "weight": "527561695272.42000000"
  },
  {
    "name": "bike",
    "amount": "14",
    "weight": "9914795.00000000"
  },
  {
    "name": "truck",
    "amount": "92",
    "weight": "999147.00000000"
  },
  {
    "name": "plane",
    "amount": "200",
    "weight": "819002.68900000"
  },
  {
    "name": "train",
    "amount": "4",
    "weight": "89129.70000000"
  }
]

When numbers are represented by numeric values

If weight values were represented by numeric values (i.e. taking into account the recommendation), it would not be necessary to perform the tonumber conversion:

jq -r 'sort_by(.weight) | reverse' input.json

Upvotes: 2

Related Questions