【问题标题】:STL name for the "map" functional programming function“map”函数式编程函数的 STL 名称
【发布时间】:2010-08-27 00:02:50
【问题描述】:

我希望能够写出类似的东西

char f(char);
vector<char> bar;
vector<char> foo = map(f, bar);

transform 函数看起来很相似,但它不会自动生成结果集合的大小。

【问题讨论】:

  • 我认为有些人的 Perl 太多了。我曾经尝试在 C++ 中实现类似的东西,但很快它就变得非常低效:与 C++ 不同,Perl 具有高级优化器,它知道数组、哈希或字符串是什么,并相应地优化对它们的操作。
  • STL 有std::map 作为集合。您可以在任何其他命名空间中拥有自己的map
  • @Dummy: map 存在于 Perl、Python 和 Lisps 中;这是一个方便的高级构造,可以简单地描述一个常见的操作。
  • @MSalters:这更像是搜索 STL 中映射操作的问题,而不是实际名称。 :-)
  • 你现在正在寻找的东西被称为“范围”,并且作为外部库存在,并且最终会在某个时候出现在语言标准本身中。

标签: c++ map-function


【解决方案1】:

您可以在&lt;iterator&gt; 中使用std::back_inserter,尽管提供前面的大小更有效。例如:

string str = "hello world!", result;
transform(str.begin(), str.end(), back_inserter(result), ::toupper);
// result == "HELLO WORLD!"

【讨论】:

  • +1 -- 您也可以使用std::vector&lt;t&gt;::reserve 来消除效率损失。
【解决方案2】:

这个问题是在 C++11 标准生效之前提出的......现在我们有 std::transform() 作为函数式编程“映射”的(丑陋的)等价物。使用方法如下:

auto f(char) -> char; // or if you like: char f(char)
vector<char> bar;
vector<char> foo;
// ... initialize bar somehow ...
std::transform(bar.begin(), bar.end(), std::back_inserter(foo), f);

【讨论】:

    【解决方案3】:

    要完成这项工作,您需要以下观察结果:

    1. 为了提高分配效率,map 函数应该完成这项工作。相反,它应该将其参数保存在一个临时对象中(在您的情况下,这将是 class map::result&lt;char(*)(char), vector&lt;char&gt; &gt; 的一个实例)
    2. map::result 临时应具有template &lt;typename T&gt; operator T 转换。
    3. map::result 分配给std::vector&lt;char&gt; 时,这种转换是唯一可行的。
    4. 在转换运算符class map::result&lt;char(*)(char), vector&lt;char&gt; &gt;::operator vector&lt;char&gt; 中有输入和返回类型,以及映射函数。此时,您可以有效地转换输入。

    &lt;edit&gt;

    代码

    template<typename CONT, typename FUNC>
    class mapresult {
        CONT const& in;
        FUNC f;
    public:
        template<typename RESULT> RESULT to() const
        {
            RESULT out;
            for (auto const& e : in) { out.push_back(f(e)); }
            return out;
        }
        template<typename RESULT> operator RESULT() const
        {
            return this->to<RESULT>();
        }
        mapresult(CONT const& in, FUNC f) : in(in), f(std::move(f)) { }
    };
    
    template<typename CONT, typename FUNC>
    auto map(CONT const& in, FUNC f) -> mapresult<CONT, FUNC>
    {
        return mapresult<CONT, FUNC>(in, f);
    }
    

    这样使用:

    using namespace std;
    char foo(char c) { return c | ('A' ^ 'a'); }
    std::string in = "Test";
    
    int main(int argc, char* argv[])
    {
        string out = map(in, &foo);
        cout << out << endl;
    
        char replace = 'e';
        cout << map(in, [replace](char c){return c == replace ? '?' : c; }).to<string>();
    }
    

    【讨论】:

    • @JohannesGerer:map 函数不知道目标容器。将映射的输出存储到std::deque&lt;char&gt; 只是发现它确实需要在std::vector&lt;char&gt; 中是低效的。
    • 一个明显的改进是对 SFINAE 的调用 .reserve(in.size()。主要问题是将结果分配给具有重载分配的类。
    【解决方案4】:

    你可以用类似的东西来模仿上面的地图语法

    template<typename T, typename A>
    T map(A(*f)(A), T & container) {
        T output;
        std::transform(container.begin(), container.end(), std::back_inserter(output), f);
        return output;
    }
    

    【讨论】:

      【解决方案5】:

      std::transform 函数可以完成这项工作,但在某些情况下性能不佳。我建议使用while 循环并事先保留大小。这个函数可以很容易地更改为与字符串或任何可映射的东西一起使用。

      template<typename T, typename C>
      std::vector<T> map(const std::vector<C> &array, auto iteratee) {
        int index = -1;
        int length = array.size();
        std::vector<T> v(length);
        while(++index < length) {
          v[index] = iteratee(array[index], index);
        }
        return v;
      }
      

      调用 array 是你想要的 std::vector 的函数 地图。

      auto result = map<int, int>(array, [](int elem, int index) {
        return elem + 10;
      });
      

      在 100 000 000 上运行地图 std::transform 花了 ~6.15s

      while 循环版本耗时约 3.90 秒

      【讨论】:

        猜你喜欢
        • 2018-10-24
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-06
        • 2017-09-06
        • 2014-10-05
        相关资源
        最近更新 更多