C++ での主とした辞書型に unordered_map があります。
通常は key/value をセットとしたアイテムから要素を構築すると思います。
この記事では、通常の方式ではなく、 2つの vector (キー用 vector とバリュー用 vector)から unordered_map を構築する例を紹介します。
key/value の vector から unordered_map を構築
pair の vector を経由して unordered_map を構築する
以下、プログラム例です。
ここでは、 vector<std::string> である k とvector<int> である v を用いて、 unordered_map を構築しています。
#include <algorithm>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
int main() {
std::vector<std::string> k{"a", "b", "c"};
std::vector<int> v{1, 2, 3};
std::vector<std::pair<std::string, int>> items;
std::transform(
k.begin(), k.end(), v.begin(), std::back_inserter(items), [](std::string k, int v) {
return std::make_pair(k, v);
});
std::unordered_map<std::string, int> m{items.begin(), items.end()};
for (const auto &[k, v] : m) {
std::cout << k << ", " << v << std::endl;
}
// Output
// c, 3
// b, 2
// a, 1
return 0;
}unordered_map には、vector<pair> のイテレータを引数にとるコンストラクタがあります。
まず k, v をくっつけて、 vector<pair> である items を構築します。
python 等で zip と呼ばれるような操作に相当します。
そのあと、items の begin と end を引数に取り、unordered_map の m を構築します。
コピーのオーバーヘッドを改善する
前述のプログラムで、処理の目的を達することができました。
しかし、文字列のコピーが2回実行されており、処理のオーバーヘッドがあります。
値のムーブによって改善したプログラム例を次に示します。
#include <algorithm>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
int main() {
std::vector<std::string> k{"a", "b", "c"};
std::vector<int> v{1, 2, 3};
std::vector<std::pair<std::string, int>> items;
std::transform(
std::make_move_iterator(k.begin()),
std::make_move_iterator(k.end()),
v.begin(),
std::back_inserter(items),
[](std::string k, int v) { return std::make_pair(k, v); });
std::unordered_map<std::string, int> m{
std::make_move_iterator(items.begin()), std::make_move_iterator(items.end())};
for (const auto &[k, v] : m) {
std::cout << k << ", " << v << std::endl;
}
// Output
// c, 3
// b, 2
// a, 1
return 0;
}ムーブイテレータを用いることによって、コピーのオーバーヘッドを抑制することができます。
ただし、ムーブ元となる vector である k と items からは、文字列の情報が失われてしまうことが注意点です。
元の vector を保全したい場合は、「前述の例のとおり値コピーする」、「shared_ptr を用いて参照コピーする」などの対処が必要です。
上記の例では v の int 型 vector に対してはムーブを行っておりません。int 型に対してはムーブができず、値コピーしかできないためです。v に対してもムーブしたい場合は v.begin() をムーブイテレータに変換することで対処可能です。
C++23 以降でのプログラム例
C++23 になると、新設の ranges パッケージを用いることで、次のような記述ができるようです。
残念ながら動作確認はできていないですが、そのうち試してみようと思います。
#include <print>
#include <ranges>
#include <string>
#include <unordered_map>
#include <vector>
int main() {
std::vector<std::string> k{"a", "b", "c"};
std::vector<int> v{1, 2, 3};
auto m = std::views::zip(k, v) | std::ranges::to<std::unordered_map<std::string, int>>();
std::println("{}", m);
return 0;
}以下に views::zip の参考サイトを掲載しておきます。




コメント