【问题标题】:How to replace a letter by another in the structure std::map如何在结构 std::map 中用另一个字母替换一个字母
【发布时间】:2021-11-22 09:44:52
【问题描述】:

假设我有一个string

std::string test = "test test";

我可以使用 replace 函数将该字符串中的字母 e 替换为另一个字母

std::replace(test.begin(), test.end(), 'e', 'E');

除了map<String, Vector<string>>,我怎样才能做到这一点?

例如

    std::map<std::string, std::vector<std::string>> myMap;
    
    myMap["test"] = {"test1,test2,test3"};
    myMap["test2"] = {"test21", "test22"};

我想把这张地图中的所有e都改成E

【问题讨论】:

  • "我想在这张地图中用 E 改变所有的 e" - 在 KeysValues 还是两者兼而有之?
  • 哦,是的......非常
  • @inver1123a 您没有向我们提供您的“解决方案”并尝试使其发挥作用,而是您要解决的实际高级问题是什么?翻开它的键位图听起来像是进入XY Problem territory
  • @inver1123a 这是一个家庭作业,我必须这样做 -- 这不是我真正要求的。作业是否说“您如何获取地图中的键并更改它们?”,还是您决定这样做?如果是前者,我确信 StackOverflow 上有重复的链接显示如何更改地图中的键。
  • @JeJo One 必须测量。添加了extract 函数 以便能够有效地执行此类操作。

标签: c++ stl


【解决方案1】:

您已经知道如何对std::string 执行替换操作。没有什么能阻止你对容器做同样的事情(基于容器包含字符串,这里就是这种情况)。

因此,对于std::map&lt;std::string, std::vector&lt;std::string&gt;&gt;,您只需遍历地图,然后遍历向量,然后以您想要的方式替换值。

但是,由于您不仅要对映射的值执行替换,还要对键执行替换,因此变得更加棘手。

如您所知,您无法修改地图中的键。所以你有两个解决方案,你可以:

  • 在地图中创建新元素 {key, value},然后删除旧元素
  • 创建新地图并覆盖原来的地图

我认为第二种解决方案是最容易实现的。


可能的实施:

我们想要的是一个函数,它可以引用地图并对其进行替换。

为了实现,我决定采用上述第二个解决方案(用新创建的覆盖地图)。

我这里选择的策略是:

  • 将流程分解为多个函数并将机制隐藏在包装类中。
  • 由于我们不需要此类的实例来运行进程,因此我们将函数标记为static
  • 只有所需的函数(供用户使用)将是 public,因此可以在类外访问/调用。

这会给我们:

using MyMap = std::map<std::string, std::vector<std::string>>; // For readability purposes

class e2E
{
    private:
        // Get a replaced version of the given string
        static std::string e2E_str(const std::string & s);

        // Get a replaced version of the given map
        static MyMap e2E_MyMap(const MyMap & m);

    public:
        // Compute the replacements over the map
        static void compute(MyMap & m);
};

e2E_str() 函数只是替换 std::string 的一个实现。
e2E_MyMap() 函数是生成新地图的过程的实现。
compute() 函数只是覆盖的实现(设计简单)。

然后我们得到:

std::string e2E::e2E_str(const std::string & s)
{
    std::string r(s);
    std::replace(r.begin(), r.end(), 'e', 'E');
    return r;
}

MyMap e2E::e2E_MyMap(const MyMap & m)
{
    MyMap result;

    std::string key;
    for(const auto & [k, v] : m)
    {
        key = e2E_str(k);
        result[key] = {};

        for(const std::string & s : v)
            result[key].push_back(e2E_str(s));
    }

    return result;
}

void e2E::compute(MyMap & m)
{
    m = e2E_MyMap(m);
}

测试:

为了便于阅读,我们可以定义一个display() 函数来显示地图。
它可能看起来像:

void display(const MyMap & m, std::ostream & os)
{
    for(const auto & [k, v] : m)
    {
        os << k << ":\n";
        for(const std::string & s : v)
            os << "   " << s << '\n';
    }
    os << std::endl;
}

然后我们可以如下调用我们的替换函数:

int main()
{
    // Create the map
    MyMap my_map {{"test1", {"There", "That", "Word", "The"}}, {"test2", {"This", "Where"}}};

    // Display the map contents before the replacement operation
    display(my_map, std::cout);

    // Perform the replacements
    e2E::compute(my_map);

    // Display the map contents after the replacement operation
    display(my_map, std::cout);

    return 0;
}

如果您想快速执行并检查此测试的结果click here

【讨论】:

    【解决方案2】:

    对于 C++17 之前的解决方案,我建议创建一个新的 map,就像 @Fareanor 所展示的那样。

    如果您可以使用 C++17 或更高版本,那么还有另一个选项不需要第二个映射,但涉及从映射中提取每个携带数据的节点,对其进行修改(包括 Key) 然后将节点重新插入到地图中。

    Key 仍在地图中时修改它的相同限制,因此,循环遍历 Key/Value 对映射,一次取出一个节点,更改它 - 并将其放回映射中。

    伪版本:

    for(it = myMap.begin(); it != myMap.end(); <no increment> ) {
    
        next = it + 1;               // save the iterator to next element because ...
        mapnode = myMap.extract(it); // ... `extract` invalidates `it`
    
        // modify the Key
        cap_e(mapnode.key());        // cap_e() capitalizes 'e' in a string
    
        // modify the mapped Value
        for every str in mapnode.mapped():
            cap_e(str)
    
        // re-insert the modified node
        myMap.insert(move(mapnode));
    
        it = next;                   // set the iterator `it` to what was saved at the top
    }
    

    【讨论】:

    • 哦,太好了!我不知道从 C++17 开始我们可以将手弄脏地图机器。话虽如此,我不相信如果要在之后修改密钥,应该选择 std::map 作为数据的容器。
    • @Fareanor 有时需要更改键,正如您所展示的,以前的方法是 1)删除键并使用新键重新插入值,或者 2)创建一个全新的映射做过。在我看来,node-hack 是一种降低成本的好方法——尽管改变地图中的键肯定会很昂贵。
    猜你喜欢
    • 2016-06-13
    • 1970-01-01
    • 2023-03-10
    • 2014-11-18
    • 1970-01-01
    • 2017-12-14
    • 1970-01-01
    • 2017-04-18
    • 2021-03-17
    相关资源
    最近更新 更多