(无序)映射键和值修改的最佳实践
The best practice for (unordered) map keys and values modification
给出了 map<long long, vector<long long>>
形式的地图。必须将所有键和值取模某个整数 N
。有些键可以合并,相应的值必须相应地连接。例如,映射 {{1,{2,6,4}}, {5,{8,4,9}}, {10,{5,1,7}}}
应该等于 {{1,{2,1,4}}, {0,{0,1,2,3,4}}}
在减少模 5 之后。
我的方法是使用新地图,但我认为应该有更好的方法。
已添加代码
vector<long long> tmp;
//integer N, for example N = 5
int N = 5;
unordered_map<long long, vector<long long>> map;
//temporary map
unordered_map<long long, vector<long long>> map_tmp;
for (auto & x : map)
{
tmp.clear();
for (auto & y : x.second) tmp.push_back(y % N);
ind = x.first % N;
map_tmp[ind].insert(map_tmp[ind].end(), tmp.begin(), tmp.end());
sort(map_tmp[ind].begin(), map_tmp[ind].end());
map_tmp[ind].erase(unique(map_tmp[ind].begin(), map_tmp[ind].end()), map_tmp[ind].end());
}
map = map_tmp;
有时 for
循环可能是做某事最简单、最清晰的方法。
map<long long, vector<long long>> result;
for (const auto& [key, vec] : input) {
process (result[key%5], vec);
}
和 process
通过(非 const)引用获取 vector
并附加第二个(const)参数的缩减值。
更新
看到您 post 编写的代码后,我有几个建议:
- 改用
set
。您正在花费多个步骤来附加新值,将整个事物排序在一起,然后删除重复项。只需使用 set
即可自动维护每个值的单个副本。
- 在循环中使用结构化绑定。您可以将它们命名为
key
和 vec
而不是 x.second
和 x.first
,就像我之前的 post.
- 假设您仍然需要
tmp
,请在调用 .clear()
的地方声明它,而不是在代码的顶部声明它。您不需要每次循环都清除它;自然每次循环都是空的。
既然地图中的值显然是唯一的,并且在应用模运算后值包含唯一项,那么您应该使用不同的数据结构。例如:
using Map = std::unordered_map<int, std::set<int>>;
std::set
将处理给定键的项目的唯一性和顺序。
现在整个技巧是检查 std::unordered_map
和 std::set
的 API 以及如何将项目插入到那里。参见:
注意 return 值:std::pair<iterator,bool>
它为您提供指向 map/set 中插入或令人兴奋的项目的迭代器。
知道写一个能够满足你要求的代码是很简单的:
using Map = std::unordered_map<int, std::set<int>>;
Map moduloMap(const Map& in, int mod)
{
Map out;
for (const auto& [k, s] : in) {
if (s.empty())
continue;
auto& destSet = out.insert({ k % mod, {} }).first->second;
for (auto x : s) {
destSet.insert(x % mod);
}
}
return out;
}
给出了 map<long long, vector<long long>>
形式的地图。必须将所有键和值取模某个整数 N
。有些键可以合并,相应的值必须相应地连接。例如,映射 {{1,{2,6,4}}, {5,{8,4,9}}, {10,{5,1,7}}}
应该等于 {{1,{2,1,4}}, {0,{0,1,2,3,4}}}
在减少模 5 之后。
我的方法是使用新地图,但我认为应该有更好的方法。
已添加代码
vector<long long> tmp;
//integer N, for example N = 5
int N = 5;
unordered_map<long long, vector<long long>> map;
//temporary map
unordered_map<long long, vector<long long>> map_tmp;
for (auto & x : map)
{
tmp.clear();
for (auto & y : x.second) tmp.push_back(y % N);
ind = x.first % N;
map_tmp[ind].insert(map_tmp[ind].end(), tmp.begin(), tmp.end());
sort(map_tmp[ind].begin(), map_tmp[ind].end());
map_tmp[ind].erase(unique(map_tmp[ind].begin(), map_tmp[ind].end()), map_tmp[ind].end());
}
map = map_tmp;
有时 for
循环可能是做某事最简单、最清晰的方法。
map<long long, vector<long long>> result;
for (const auto& [key, vec] : input) {
process (result[key%5], vec);
}
和 process
通过(非 const)引用获取 vector
并附加第二个(const)参数的缩减值。
更新
看到您 post 编写的代码后,我有几个建议:
- 改用
set
。您正在花费多个步骤来附加新值,将整个事物排序在一起,然后删除重复项。只需使用set
即可自动维护每个值的单个副本。 - 在循环中使用结构化绑定。您可以将它们命名为
key
和vec
而不是x.second
和x.first
,就像我之前的 post. - 假设您仍然需要
tmp
,请在调用.clear()
的地方声明它,而不是在代码的顶部声明它。您不需要每次循环都清除它;自然每次循环都是空的。
既然地图中的值显然是唯一的,并且在应用模运算后值包含唯一项,那么您应该使用不同的数据结构。例如:
using Map = std::unordered_map<int, std::set<int>>;
std::set
将处理给定键的项目的唯一性和顺序。
现在整个技巧是检查 std::unordered_map
和 std::set
的 API 以及如何将项目插入到那里。参见:
注意 return 值:std::pair<iterator,bool>
它为您提供指向 map/set 中插入或令人兴奋的项目的迭代器。
知道写一个能够满足你要求的代码是很简单的:
using Map = std::unordered_map<int, std::set<int>>;
Map moduloMap(const Map& in, int mod)
{
Map out;
for (const auto& [k, s] : in) {
if (s.empty())
continue;
auto& destSet = out.insert({ k % mod, {} }).first->second;
for (auto x : s) {
destSet.insert(x % mod);
}
}
return out;
}