admin管理员组

文章数量:1394778

I have the following json format. It's basically a representation of the calendar:

{"month1": {"day1":{...}, "day2": {...}}, "month2": {...}}

I'd like to sort it such that both the months and the days will be in numeric order. The below input is the output of jq -S, but as you see it's sorted like: 1,10,2, and I'd like to sort it like 1,2,10. How can I do that with jq?

Input:

{
    "1":{"1":{"foo":"bar"},"10":{"foo":"bar"},"2":{"foo":"bar"}},
    "10":{"1":{"foo":"bar"},"10":{"foo":"bar"},"2":{"foo":"bar"}},
    "2":{"1":{"foo":"bar"},"10":{"foo":"bar"},"2":{"foo":"bar"}}
}

Expected output:

{
    "1":{"1":{"foo":"bar"},"2":{"foo":"bar"},"10":{"foo":"bar"}},
    "2":{"1":{"foo":"bar"},"2":{"foo":"bar"},"10":{"foo":"bar"}},
    "10":{"1":{"foo":"bar"},"2":{"foo":"bar"},"10":{"foo":"bar"}}
}

update:

I want to have this sorting for 2 reasons:

  1. it's nice to have it ordered in the "human logical" way.
  2. I'd like to be able to diff 2 similar jsons in this format. (I guess this would work even with the current order)

For all the downvoters: jq -S wasn't invented by me and it does sort the keys of an object. Many use jq as a json prettifier/formatter/identer, so I think this is a legitimate use-case. You don't have to sort your json objects, that's fine, but why down-voting?

I have the following json format. It's basically a representation of the calendar:

{"month1": {"day1":{...}, "day2": {...}}, "month2": {...}}

I'd like to sort it such that both the months and the days will be in numeric order. The below input is the output of jq -S, but as you see it's sorted like: 1,10,2, and I'd like to sort it like 1,2,10. How can I do that with jq?

Input:

{
    "1":{"1":{"foo":"bar"},"10":{"foo":"bar"},"2":{"foo":"bar"}},
    "10":{"1":{"foo":"bar"},"10":{"foo":"bar"},"2":{"foo":"bar"}},
    "2":{"1":{"foo":"bar"},"10":{"foo":"bar"},"2":{"foo":"bar"}}
}

Expected output:

{
    "1":{"1":{"foo":"bar"},"2":{"foo":"bar"},"10":{"foo":"bar"}},
    "2":{"1":{"foo":"bar"},"2":{"foo":"bar"},"10":{"foo":"bar"}},
    "10":{"1":{"foo":"bar"},"2":{"foo":"bar"},"10":{"foo":"bar"}}
}

update:

I want to have this sorting for 2 reasons:

  1. it's nice to have it ordered in the "human logical" way.
  2. I'd like to be able to diff 2 similar jsons in this format. (I guess this would work even with the current order)

For all the downvoters: jq -S wasn't invented by me and it does sort the keys of an object. Many use jq as a json prettifier/formatter/identer, so I think this is a legitimate use-case. You don't have to sort your json objects, that's fine, but why down-voting?

Share Improve this question edited Mar 28 at 10:59 Gavriel asked Mar 27 at 8:45 GavrielGavriel 19.2k12 gold badges72 silver badges115 bronze badges 2
  • Why do you need it? – choroba Commented Mar 27 at 10:39
  • Because I want to process different sources (I'll generate the json from other formats) but at the end I'd like to be able to diff the prettified jsons. Also it's nice to be able to look at it in an editor and see that after January it's Fenruary and not October. – Gavriel Commented Mar 28 at 10:51
Add a comment  | 

1 Answer 1

Reset to default 2

The wrong goal

While the encoding of a JSON object inherently reveals some ordering of its items, JSON objects actually don't convey the notion of an order (only JSON arrays do). So, forcefully inducing a specific order onto its items is ephemeral at best. It may hold for the document's current representation, but any subsequent processor could very well just disregard this configuration, and break this order without reason, without giving any notice, and, most importantly, without violating the JSON specs. Therefore, relying on a specific order apparent in a given encoding (the actual representation as a stream of characters) is a computational bug, and should therefore be discouraged.

But if you must

That said, using jq, you can turn the items of an object into an array of key-value pairs using to_entries, sort that array by the numeric representation of each .key using sort_by and to_number, and then re-compose the object based on that array using from_entries, which jq will perform in the order of the array. Finally, apply this function composition to both the root node . and its children .[].

A word of caution

Again, note that this side-effect is just the actual behavior of jqlang/jq (but not of itchyny/gojq, for example), and is nowhere guaranteed to stay that way. However, the current and several latest versions of jqlang/jq (at least until v1.7) seem to be implemented this way.

(.[], .) |= (to_entries | sort_by(.key | tonumber) | from_entries)
{
  "1": {
    "1": {
      "foo": "bar"
    },
    "2": {
      "foo": "bar"
    },
    "10": {
      "foo": "bar"
    }
  },
  "2": {
    "1": {
      "foo": "bar"
    },
    "2": {
      "foo": "bar"
    },
    "10": {
      "foo": "bar"
    }
  },
  "10": {
    "1": {
      "foo": "bar"
    },
    "2": {
      "foo": "bar"
    },
    "10": {
      "foo": "bar"
    }
  }
}

Demo

本文标签: sortingsort json object numerically by keyStack Overflow