(无序)映射键和值修改的最佳实践

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 编写的代码后,我有几个建议:

  1. 改用 set。您正在花费多个步骤来附加新值,将整个事物排序在一起,然后删除重复项。只需使用 set 即可自动维护每个值的单个副本。
  2. 在循环中使用结构化绑定。您可以将它们命名为 keyvec 而不是 x.secondx.first,就像我之前的 post.
  3. 假设您仍然需要 tmp,请在调用 .clear() 的地方声明它,而不是在代码的顶部声明它。您不需要每次循环都清除它;自然每次循环都是空的。

既然地图中的值显然是唯一的,并且在应用模运算后值包含唯一项,那么您应该使用不同的数据结构。例如:

using Map = std::unordered_map<int, std::set<int>>;

std::set 将处理给定键的项目的唯一性和顺序。

现在整个技巧是检查 std::unordered_mapstd::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;
}

Live demo with tests