std::map に「挿入か更新をする」ときの idiom をすぐに忘れてしまうのでメモしておく.
std::map<S, T> mp;
と宣言されているとする.
1. 無条件で,s の値を t にする
通常は次で良い:
mp[s] = t;
もともと s が有ったか無かったのかも知りたい場合や,s へのイタレータも欲しい場合には,次のようにする:
auto [it, b] = mp.insert_or_assign(s, t);
b には,挿入が行われたかどうかが設定されるので,b が false なら,もともとキー s が存在していたことがわかる.it は s へのイタレータ.
2. キー s が無ければ,値を t にする.
次のように書くと,s の探索が2回走ってしまう.
if (mp.find(s) == mp.end()) mp[s] = t;
次のようにすれば 1回ですむ.
mp.emplace(s, t);
もともと s が有ったか無かったのかも知りたい場合や,s へのイタレータも欲しい場合には,次のようにする:
auto [it, b] = mp.emplace(s, t);
b には,挿入が行われたかどうかが設定されるので,b が false なら,もともとキー s が存在していたことがわかる.it は s へのイタレータ.
3. キー s が無く,さらになんらかの条件も成り立てば,s の値を t にする.
次のように書くと,s の探索が2回走ってしまう.
if (mp.find(s) == mp.end() and some_condition()) mp[s] = t;
次のようにすれば 1 回ですむ.
auto it = mp.lower_bound(s);
if ((it == mp.end() or it->first != s) and some_condition()) mp.emplace_hint(it, s, t);
lower_bound の戻り値を hint に使うのがポイント.(ChatGPTに教えてもらいました)