“地图”的STL名称函数式编程函数

发布于 2024-09-16 01:26:13 字数 178 浏览 5 评论 0 原文

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

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

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

I would like to be able to write something like

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

The transform function appears to be similar, but it will not autogenerate the size of the resultant collection.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

堇色安年 2024-09-23 01:26:14

您可以在 中使用 std::back_inserter,尽管在​​前面提供大小会更有效。例如:

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

You can use std::back_inserter in <iterator>, although providing the size in front is more efficient. For example:

string str = "hello world!", result;
transform(str.begin(), str.end(), back_inserter(result), ::toupper);
// result == "HELLO WORLD!"
太阳男子 2024-09-23 01:26:14

这个问题是在 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);

This question was asked before the C++11 standard went into effect... nowadays we have std::transform() as the (ugly) equivalent of a functional programming 'map'. Here's how to use it:

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);
笑忘罢 2024-09-23 01:26:14

为了使这项工作正常进行,您需要注意以下几点:

  1. 为了使分配高效,map 函数不应该执行这项工作。相反,它应该将其参数保存在临时对象中(在您的情况下,这将是 class map::result > 的实例)
  2. 这个 map::result 临时文件应该有一个 template 运算符 T 转换。
  3. 当将 map::result 分配给 std::vector 时,此转换是唯一可行的。
  4. 在转换运算符class map::result中>::operator vector 您拥有输入和返回类型以及映射函数。此时您可以有效地转换输入。

代码

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>();
}

To make this work, you'll need the following observations:

  1. To make the assignment efficient, the map function should not do the work. Instead, it should save its arguments in a temporary object (in your case, that would be an instance of class map::result<char(*)(char), vector<char> >)
  2. This map::result temporary should have an template <typename T> operator T conversion.
  3. When the map::result is assigned to a std::vector<char>, this conversion is the only viable.
  4. In the conversion operator class map::result<char(*)(char), vector<char> >::operator vector<char> you have the input and return type, and the mapping function. At this point you can effectively transform the inputs.

<edit>

Code

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);
}

Use like this:

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>();
}
萝莉病 2024-09-23 01:26:14

您可以使用类似的内容来模仿上面的映射语法

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;
}

You can mimic the map syntax above with something like

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;
}
仄言 2024-09-23 01:26:14

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.15 秒,

而 while 循环版本花费了约 3.90 秒

The std::transform function does the job, but isn't performant in some cases. I would suggest using a while loop and reserving the size before hand. This function can easily be changed to be used with strings or any thing mappable for that matter.

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;
}

Calling the function where array is the std::vector you want to
map.

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

Running map on 100 000 000
with std::transform took ~6.15s

the while loop version took ~3.90s

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文