nlohmann::fifo_map works through the adapter that has always been documented for it, and preserves the insertion order. Restore its mention in the object order page, which was dropped together with the tsl::ordered_map one: unlike ordered_map it keeps a lookup index, so it is the insertion-ordered option without the quadratic cost. gtl::flat_hash_map and folly::sorted_vector_map work as well, the latter through an alias that drops the allocator, whose value type it disagrees on. gtl::btree_map does not, for the same reason as the other btree containers. None of the Qt containers can be used, each for its own reason: QMap has no value_type, QHash iterators yield the mapped value rather than a pair, QList has no max_size(), QByteArray spells empty() as isEmpty(), and QString is UTF-16. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
3.6 KiB
Object Order
The JSON standard defines objects as "an unordered collection of zero or more name/value pairs". As such, an implementation does not need to preserve any specific order of object keys.
Default behavior: sort keys
The default type nlohmann::json uses a std::map to store JSON objects, and thus stores object keys sorted alphabetically.
??? example
```cpp
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
json j;
j["one"] = 1;
j["two"] = 2;
j["three"] = 3;
std::cout << j.dump(2) << '\n';
}
```
Output:
```json
{
"one": 1,
"three": 3,
"two": 2
}
```
Alternative behavior: preserve insertion order
If you do want to preserve the insertion order, you can use the type nlohmann::ordered_json.
??? example
```cpp
--8<-- "examples/ordered_json.cpp"
```
Output:
```json
--8<-- "examples/ordered_json.output"
```
Alternatively, nlohmann::fifo_map also preserves the insertion order and, unlike ordered_map, keeps a lookup index, so it does not have the quadratic cost described below. It is used through a small adapter (integration).
If the order does not matter and you only want faster lookup, boost::unordered_flat_map, absl::flat_hash_map, absl::node_hash_map, and several other hash maps work through an adapter that restores the template argument order basic_json expects; see Template Parameter Requirements. Note these are unordered, not insertion-ordered.
tsl::ordered_map cannot be used: its iterators expose the mapped value as const, while basic_json needs to modify it in place.
The ordered_map behind nlohmann::ordered_json is deliberately minimal and has no lookup
index, so every key access is a linear scan and building an object of n keys costs O(n²). This is unnoticeable at
typical object sizes but becomes significant for objects with many thousands of keys; see
ordered_map complexity. The alternatives above keep a lookup index and do not
have this cost.
Notes on parsing
Note that you also need to call the right parse function when reading from a file.
Assume file input.json contains the JSON object above:
{
"one": 1,
"two": 2,
"three": 3
}
!!! success "Right way"
The following code correctly calls the `parse` function from `nlohmann::ordered_json`:
```cpp
std::ifstream i("input.json");
auto j = nlohmann::ordered_json::parse(i);
std::cout << j.dump(2) << std::endl;
```
The output will be:
```json
{
"one": 1,
"two": 2,
"three": 3
}
```
??? failure "Wrong way"
The following code incorrectly calls the `parse` function from `nlohmann::json` which does not preserve the
insertion order, but sorts object keys. Assigning the result to `nlohmann::ordered_json` compiles, but does not
restore the order from the input file.
```cpp
std::ifstream i("input.json");
nlohmann::ordered_json j = nlohmann::json::parse(i);
std::cout << j.dump(2) << std::endl;
```
The output will be:
```json
{
"one": 1,
"three": 3,
"two": 2
}
```