Files
json/docs/mkdocs/docs/features/object_order.md
T
Niels LohmannandGitHub c2e1cc50e0 docs: document the complexity of ordered_map operations (#5353)
* docs: document the complexity of ordered_map operations

ordered_map stores its elements in a std::vector in insertion order and
has no lookup index, so emplace, operator[], at, find, count, erase, and
insert are all linear scans. The documentation stated no complexity for
any operation, neither in ordered_map.md nor in ordered_json.md.

Add a per-operation complexity table and note the consequence: building
or parsing an ordered_json object of n keys is O(n^2). Measured with
-O2 -DNDEBUG for parsing a flat object of n keys, ordered_json is 5x
slower than json at n=2000 and 54x slower at n=16000, with the timings
quadrupling per doubling of n. Cross-reference the table from
ordered_json.md and from the object order page, which recommends
ordered_json without mentioning the cost.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* docs: move the Complexity section after Member functions

scripts/check_structure.py enforces a fixed section order for pages under
docs/mkdocs/docs/api, in which Complexity comes after Member functions.
The section had been placed right after Iterator invalidation, which made
ci_test_build_documentation fail with structure/section_order.

No content change beyond the move; the table columns are realigned to the
narrower content.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-08-04 08:45:35 +02:00

3.0 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, you can use a more sophisticated ordered map like tsl::ordered_map (integration) or nlohmann::fifo_map (integration).

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
}
```