C++ 使用迭代器按元素数而不是键从std::map获取子映射

C++ 使用迭代器按元素数而不是键从std::map获取子映射,c++,C++,我有一个std::map,我需要在这个映射上执行一个线程任务,将映射划分为子映射,并将每个子映射传递给一个线程 使用std::vector我可以很容易地获得子向量,方法如下: #包括 #包括 内部主(空) { 尺寸=0; size\u t num\u elms=100;//组合值 std::vector full;//假设填充了内容 标准::矢量子(标准::开始(完整)+关闭,标准::开始(完整)+关闭+数值); off=off+num_elms; } 但是,对std::map执行相同操作会产

我有一个
std::map
,我需要在这个映射上执行一个线程任务,将映射划分为子映射,并将每个子映射传递给一个线程

使用
std::vector
我可以很容易地获得子向量,方法如下:

#包括
#包括
内部主(空)
{
尺寸=0;
size\u t num\u elms=100;//组合值
std::vector full;//假设填充了内容
标准::矢量子(标准::开始(完整)+关闭,标准::开始(完整)+关闭+数值);
off=off+num_elms;
}
但是,对
std::map
执行相同操作会产生编译错误

#包括
#包括
#包括
内部主(空)
{
尺寸=0;
大小/数量=100;
标准::地图完整;
标准::映射子(标准::开始(完全)+关闭,
标准::开始(完全)+关闭+num_elms);
off=off+num_elms;
}
这与其他
std::map
“类型”相同。从我收集到的信息来看,这就是迭代器

// Minimal range-for support
template <typename Iter>
struct Range {
    Range (Iter b, Iter e) : b(b), e(e) {}
    Iter b;
    Iter e;

    Iter begin() const { return b; }
    Iter end() const { return e; }
};

// some shorter aliases
using Map = std::map<std::string, std::vector<std::string>>;
using MapView = Range<Map::const_iterator>;

// not necessarily the whole map
void print_map(MapView map) {
    for (const auto& [key, value] : map)
    {
        std::cout << "key: " << key << "\nvalues\n";
        for (const auto& elm : value)
        {
            std::cout << "\t" << elm << "\n"; 
        }
    }
}

int main(void)
{
    Map full;

    full["aa"] = {"aa", "aaaa", "aabb"};
    full["bb"] = {"bb", "bbbbb", "bbaa"};
    full["cc"] = {"cc", "cccc", "ccbb"};
    full["dd"] = {"dd", "dd", "ddcc"};

    // can still print the whole map
    print_map({ map.begin(), map.end() });

    size_t num_elms = 2;
    size_t num_full_views = full.size() / num_elms;
    
    std::vector<MapView> views;

    auto it = full.begin();
    for (size_t i = 0; i < num_full_views; ++i) {
        auto next = std::next(it, num_elms);
        views.emplace_back(it, next);
        it = next;
    }

    if (it != full.end()) {
        views.emplace_back(it, full.end());
    }

    for (auto view : views) {
        print_map(view);
    }
}
可以提取密钥并执行类似于此解决方案的操作:

#包括
#包括
#包括
#包括
无效打印映射(常量标准::映射和映射)
{
对于(常量自动和[key,value]:\u映射)
{

std::cout稍加调整,您就可以相当轻松地将范围传递给
print_map
,并通过在迭代器上调用
std::next
来划分地图

// Minimal range-for support
template <typename Iter>
struct Range {
    Range (Iter b, Iter e) : b(b), e(e) {}
    Iter b;
    Iter e;

    Iter begin() const { return b; }
    Iter end() const { return e; }
};

// some shorter aliases
using Map = std::map<std::string, std::vector<std::string>>;
using MapView = Range<Map::const_iterator>;

// not necessarily the whole map
void print_map(MapView map) {
    for (const auto& [key, value] : map)
    {
        std::cout << "key: " << key << "\nvalues\n";
        for (const auto& elm : value)
        {
            std::cout << "\t" << elm << "\n"; 
        }
    }
}

int main(void)
{
    Map full;

    full["aa"] = {"aa", "aaaa", "aabb"};
    full["bb"] = {"bb", "bbbbb", "bbaa"};
    full["cc"] = {"cc", "cccc", "ccbb"};
    full["dd"] = {"dd", "dd", "ddcc"};

    // can still print the whole map
    print_map({ map.begin(), map.end() });

    size_t num_elms = 2;
    size_t num_full_views = full.size() / num_elms;
    
    std::vector<MapView> views;

    auto it = full.begin();
    for (size_t i = 0; i < num_full_views; ++i) {
        auto next = std::next(it, num_elms);
        views.emplace_back(it, next);
        it = next;
    }

    if (it != full.end()) {
        views.emplace_back(it, full.end());
    }

    for (auto view : views) {
        print_map(view);
    }
}

一种稍微不同的方法是使用C++17中添加的一种执行策略,如。在下面的示例中,使用了实例
std::execution::par

#include <execution>

    // ...

    std::for_each(std::execution::par, full.begin(), full.end(), [](auto& p) {
        // Here you are likely using a thread from a built-in thread pool
        auto& vec = p.second;
        // do work with "vec"
    });
#包括
// ...
std::for_each(std::execution::par,full.begin(),full.end(),[](自动&p){
//在这里,您可能使用内置线程池中的线程
自动&vec=p.second;
//与“vec”一起工作
});

std::end(完整)+off+num_elms
毫无意义您第一次尝试使用maps时遇到的问题是,map迭代器不是随机访问迭代器,因此您不能向迭代器中添加数字。但是您可以使用此函数推进迭代器:旁白:将元素复制到子映射似乎是一种浪费,您能识别成对的
map::const_迭代器吗
而不是线程查看?我用
std::next
删除了我的答案,因为你的问题似乎根本不正确。如果你发现自己用
std::map
索引,那么
std::map
不是正确的工具。@AyxanHaqverdili感谢你抓住了这个问题,它自然应该是
std::begin()
。假设
std::next
is使用for循环。然后vector::emplace\u back使用另一个for循环来迭代相同的元素。这就是一个效率低下的事情。@AyxanHaqverdili“这样一个效率低下的事情”仍然可以“足够快”当然,但是
map
显然不是设计来做这件事的。这是一种滥用。我们总共迭代了两次完整的map。我几乎不会称之为滥用。
map
是设计用来作为一个范围的。
drop\u view
take\u view
不是新颖的想法。这是一个很棒的想法。甚至可以使用
paru unseq
m大部分时间。@AyxanHaqverdili谢谢。我同意
par_unseq
,并且我已经比较了
par
par_unseq
几次,我总是得到非常相似的性能改进(与正常顺序运行相比)-但是,理论上它可能更快。