# nlohmann::ordered_map
```cpp
template,
class Allocator = std::allocator>>
struct ordered_map : std::vector, Allocator>;
```
A minimal map-like container that preserves insertion order for use within [`nlohmann::ordered_json`](ordered_json.md)
(`nlohmann::basic_json`).
## Template parameters
`Key`
: key type
`T`
: mapped type
`IgnoredLess`
: comparison function (ignored and only added to ensure compatibility with `#!cpp std::map`)
`Allocator`
: allocator type
## Iterator invalidation
The type uses a `std::vector` to store object elements. Therefore, adding elements can yield a reallocation in which
case all iterators (including the `end()` iterator) and all references to the elements are invalidated.
When the storage grows, the keys are copied and the mapped values are moved to the new storage. A plain `std::vector`
would copy the whole elements instead, because their `#!cpp const` keys make them not nothrow move constructible; for
[`ordered_json`](ordered_json.md), this would be a deep copy of every nested value. The values are only copied if
`T` is not default constructible or not nothrow move assignable.
## Member types
- **key_type** - key type (`Key`)
- **mapped_type** - mapped type (`T`)
- **Container** - base container type (`#!cpp std::vector, Allocator>`)
- **iterator**
- **const_iterator**
- **size_type**
- **value_type**
- **key_compare** - key comparison function
```cpp
std::equal_to // until C++14
std::equal_to<> // since C++14
```
## Member functions
- (constructor)
- (destructor)
- **emplace**
- **operator\[\]**
- **at**
- **erase**
- **count**
- **find**
- **insert**
## Exception safety
**emplace**, **operator\[\]**, and **insert(value)** have the strong exception guarantee: if an exception is thrown (for
instance, because copying a key or allocating memory fails), the contents of the container are unchanged.
## Complexity
Because the elements are stored in a `std::vector` in insertion order, there is no index to look a key up by. Every
key-based operation performs a **linear scan** over the stored elements. With `n` denoting the number of elements in the
container:
| Operation | Complexity | Note |
|----------------------------------------|----------------|----------------------------------------------------------|
| **emplace** | O(n) | scans for an existing key, then appends (amortized O(1)) |
| **operator\[\]** | O(n) | delegates to **emplace** (non-const) or **at** (const) |
| **at** | O(n) | throws `#!cpp std::out_of_range` if the key is not found |
| **find** | O(n) | |
| **count** | O(n) | the result is always 0 or 1 |
| **erase(key)** | O(n) | scan, then move the remaining elements one position down |
| **erase(pos)**, **erase(first, last)** | O(n) | moves all elements after the erased range |
| **insert(value)** | O(n) | equivalent to **emplace** |
| **insert(first, last)** | O((n + m) * m) | for `m` inserted elements |
This differs from `#!cpp std::map`, where the same operations are O(log n).
!!! warning "Quadratic cost of building large objects"
Because every insertion scans all elements inserted so far, building an object of `n` distinct keys costs
**O(n²)** in total. This applies to filling an [`ordered_json`](ordered_json.md) object key by key (with
`operator[]`, `emplace`, or `insert`) and, for now, to reading one with a binary reader such as
[`from_cbor`](basic_json/from_cbor.md) ([#6104](https://github.com/nlohmann/json/issues/6104)). Parsing JSON text
is not affected: the parser finds the keys of an object with many members in a hash table and takes linear time.
The cost is negligible for the object sizes typically found in configuration files or API payloads, but it grows
steeply for machine-generated objects with many thousands of keys. Measured with Apple clang 21, `-O2 -DNDEBUG`,
arm64, for a flat object of `n` keys (best of seven runs):
| `n` | `json::parse` | `ordered_json::parse` | `ordered_json`, key by key | `ordered_json::from_cbor` |
|--------|---------------|-----------------------|----------------------------|---------------------------|
| 2000 | 0.3 ms | 0.1 ms | 4.5 ms | 4.4 ms |
| 4000 | 0.5 ms | 0.2 ms | 17.1 ms | 16.8 ms |
| 8000 | 0.9 ms | 0.3 ms | 67.0 ms | 66.8 ms |
| 16 000 | 2.0 ms | 0.7 ms | 282.4 ms | 282.4 ms |
If key order matters for objects of that size, consider a container with a lookup index, such as
[`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map)
([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)), as the object type — see
[object order](../features/object_order.md).
## Examples
??? example
The example shows the different behavior of `std::map` and `nlohmann::ordered_map`.
```cpp
#include
#include
// simple output function
template
void output(const char* prefix, const Map& m)
{
std::cout << prefix << " = { ";
for (auto& element : m)
{
std::cout << element.first << ":" << element.second << ' ';
}
std::cout << "}" << '\n';
}
int main()
{
// create and fill two maps
nlohmann::ordered_map m_ordered;
m_ordered["one"] = "eins";
m_ordered["two"] = "zwei";
m_ordered["three"] = "drei";
std::map m_std;
m_std["one"] = "eins";
m_std["two"] = "zwei";
m_std["three"] = "drei";
// output: m_ordered is ordered by insertion order, m_std is ordered by key
output("m_ordered", m_ordered);
output("m_std", m_std);
// erase and re-add "one" key
m_ordered.erase("one");
m_ordered["one"] = "eins";
m_std.erase("one");
m_std["one"] = "eins";
// output: m_ordered shows newly added key at the end; m_std is again ordered by key
output("m_ordered", m_ordered);
output("m_std", m_std);
}
```
Output:
```json
m_ordered = { one:eins two:zwei three:drei }
m_std = { one:eins three:drei two:zwei }
m_ordered = { two:zwei three:drei one:eins }
m_std = { one:eins three:drei two:zwei }
```
## See also
- [`ordered_json`](ordered_json.md) - JSON specialization preserving insertion order
- [Object Order](../features/object_order.md) - the article on object key order
## Version history
- Added in version 3.9.0 to implement [`nlohmann::ordered_json`](ordered_json.md).
- Added **key_compare** member in version 3.11.0.
- Changed in version 3.13.0: growing the storage moves the mapped values instead of copying them.