【问题标题】:How to use tolower with lambda function in map? C++如何在地图中使用 tolow 和 lambda 函数? C++
【发布时间】:2015-11-26 20:49:08
【问题描述】:

我想将存储在地图中的所有单词更改为小写。使用 lambda 函数和变换,我该怎么做?

std::map <string, int> M;
std::map<string, int> M1;

std::transform(M.begin(), M.end(), M1.begin(),
         [](pair<const string, int> const & p) { ::tolower(p.first); });

【问题讨论】:

  • 您不能更改密钥。您应该将原始地图复制到其他地图中。
  • 由于您的地图中的string,当您访问地图中的元素时,您只有const 访问权限(注意您的地图中的const string对),因此您无法编辑它们。您必须使用小写键创建一个新地图
  • @VladfromMoscow 喜欢这个?我已经编辑了我的问题。
  • 只需对项目使用正常迭代来填充 M1。这里不需要花哨的东西。

标签: c++ algorithm dictionary lambda transform


【解决方案1】:

您无法在map 中编辑,因此您必须创建新地图

类似的东西:

  • 迭代地图中的值
  • 获取密钥的副本
  • 转换为小写
  • 插入到您的结果图中:

例子:

#include <iostream>
#include <map>
#include <algorithm>

int main()
{
    std::map<std::string, int> map = {{ "HELLO", 1 }, { "WORLD", 2 }};

    std::cout << "before:\n";
    for (auto& kv : map)
    {
        std::cout << '\t' << kv.first << ":" << kv.second << '\n';
    }

    // create a new map with lowercase keys
    std::map<std::string, int> out;
    std::for_each(map.begin(), map.end(), [&](auto& kv)
        {
            std::string lower;
            std::transform(kv.first.begin(), kv.first.end(), std::back_inserter(lower), tolower);
            out[lower] = kv.second;
        });

    std::cout << "after:\n";
    for (auto& kv : out)
    {
        std::cout << '\t' << kv.first << ":" << kv.second << '\n';
    }

    return 0;
}

输出:

before:
    HELLO:1
    WORLD:2
after:
    hello:1
    world:2

【讨论】:

  • 非常感谢。赞赏。但我想在这里学习 lambda。你能告诉我如何在没有 for 循环的情况下处理 M 和 M1 吗?
  • @Dorothy 我已将地图的创建更改为使用带有 lambda 的 std::for_each。希望有帮助
【解决方案2】:

std::transform将函子的结果分配给目标范围内的元素。这意味着目标迭代器必须是与输入范围具有相同大小的范围的开始。在您的示例中,目的地是一张空地图。转换本质上是以下循环:

std::map <string, int> M;
std::map<string, int> M1;

for(auto i=M.begin(), j=M1.begin(); i != M.end(); ++i,++j)
{
    *j = f(*i);
}

递减j 对于空容器是非法的,并且对于地图没有意义,因为您无法更改密钥。

您可以从这段代码中看到,您的 lambda 也是不正确的。它应该将一个(键值)对转换为目标类型的对象。在您的情况下,目标类型是相同的。

您必须先调整目标容器的大小,例如如果它是一个向量,则调用resize,或者使用一个迭代器将赋值调整为map::insert。 STL 为此提供了适配器:

#include <map>
#include <string>
#include <cctype>
#include <iterator>
#include <algorithm>

int main() {
std::map <std::string, int> M;
std::map<std::string, int> M1;

std::transform(M.begin(), M.end(), std::inserter(M1, M1.begin()),
               [](std::pair<const std::string, int> const & p) 
{ 
    std::string lowercase;
    std::transform( p.first.begin(), p.first.end(), 
                    std::back_inserter(lowercase),
                    [](auto c) {return std::tolower(c);} );

    return std::make_pair(lowercase, p.second); 
});

return 0;
}

【讨论】:

  • make_pair ?我需要添加其他内容吗?
  • @Dorothy 我不知道你的程序中包含什么 :-) std::make_pairutility 中。您还需要 iterator 作为插入器。
  • 我都包括了。它说“没有匹配的函数调用'tolower'”。
  • @Dorothy 对不起,你是对的。 std::tolower仅适用于字符,不适用于字符串。您要么必须自己实现,要么使用一些库函数。我将更新答案中的代码。 std::tolowercctype 中。
  • 你能创建一个这样的新字符串吗?错误显示“没有匹配的构造函数用于初始化 'std::string' (aka 'basic_string, allocator>')”
【解决方案3】:

如果你想完全使用std::transform,那么你可以使用下面的方法

#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <cctype>
#include <iterator>
#include <utility>


int main ()
{
    std::map<std::string, int> m1 = { { "FIRST", 1 }, { "SECOND", 2 } };

    for ( const auto &p : m1 ) 
    {
        std::cout << p.first << '\t' << p.second << std::endl;
    }

    auto to_lower_case = []( const std::pair<const std::string, int> &p )
    {
        std::string t; t.reserve( p.first.size() );
        std::transform( p.first.begin(), p.first.end(),
                        std::back_inserter( t ), ::tolower );
        return std::make_pair( t, p.second );                        
    };

    std::cout << std::endl;

    std::map<std::string, int> m2;

    std::transform( m1.begin(), m1.end(), 
                    std::inserter( m2, m2.begin() ), to_lower_case );

    for ( const auto &p : m2 ) 
    {
        std::cout << p.first << '\t' << p.second << std::endl;
    }
}

程序输出是

FIRST   1
SECOND  2

first   1
second  2

在程序中有两次使用std::transform

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 2019-08-20
    • 2020-05-01
    • 2015-09-18
    相关资源
    最近更新 更多