在 C++ 向量的每个元素上调用函数
Posted
技术标签:
【中文标题】在 C++ 向量的每个元素上调用函数【英文标题】:Calling a function on every element of a C++ vector 【发布时间】:2012-05-09 12:49:49 【问题描述】:在 C++ 中,有没有一种方法可以在向量的每个元素上调用函数,而不使用遍历所有向量元素的循环?类似于 Python 中的“地图”。
【问题讨论】:
【参考方案1】:是的:std::for_each
。
#include <algorithm> //std::for_each
void foo(int a)
std::cout << a << "\n";
std::vector<int> v;
...
std::for_each(v.begin(), v.end(), &foo);
【讨论】:
人们会期望使用这个(而不是循环)提高速度吗? @dbliss,for_each()
的实现很可能是一个循环,因为它使用模板,所以应该没有区别。但是,使用 C++17,它们可能会引入对您完全透明的并行性,并且很可能最终会更快地开始。
std::for_each(v.begin(), v.end(), &foo);或 std::for_each(v.begin(), v.end(), foo);【参考方案2】:
您已经收到多个提到 std::for_each
的答案。
虽然这些回答了您提出的问题,但我想补充一点,至少根据我的经验,std::for_each
是标准算法中最不有用的。
我使用(例如)std::transform
,基本上是a[i] = f(b[i]);
或result[i] = f(a[i], b[i]);
比std::for_each
更频繁。许多人经常使用std::for_each
来打印集合的元素;为此,std::copy
与 std::ostream_iterator
作为目的地效果更好。
【讨论】:
这是我一直在寻找的答案,transform
比 for_each
更接近 Python 的 map
,因为 map
生成输出列表,而 for_each
调用函数但丢弃输出。
为什么不使用基于范围的 for(const auto& item : myCollection)?如果您在类或头文件/源文件中有另一个函数,或者当您使用 lambda 时,只需更少的代码。
@KulaGGin:主要是因为问题指定:“......不使用遍历所有向量元素的循环?”诚然,这可能不是最合理的要求,但是当问题具体是关于不使用循环时建议循环并不能真正回答问题。
哎呀,对不起,我的错,我错过了。我确实阅读了标题并浏览了文本。【参考方案3】:
在 C++ 11 上:您可以使用 lambda。例如:
std::vector<int> nums3, 4, 2, 9, 15, 267;
std::for_each(nums.begin(), nums.end(), [](int &n) n++; );
参考:http://en.cppreference.com/w/cpp/algorithm/for_each
【讨论】:
或者不使用 lambda 并使用基于范围的 for 循环:for(int& n: nums) n++;
。更少的代码 - 更容易理解。【参考方案4】:
如果你有 C++11,还有一个更短的方法:ranged-based for。它的目的正是如此。
std::vector<int> v 1,2,3,4,5;
for (int element : v)
std::cout << element; //prints 12345
您也可以在适当的时候对其应用引用和 const,或者在类型较长时使用 auto。
std::vector<std::vector<int>> v 1,2,3,4,5,6;
for (const auto &vec : v)
for (int element : vec)
cout << element;
cout << '\n';
输出:
123
456
【讨论】:
例如,vs2011 尚不支持此语法。至少不是我的副本。但是 +1。 @xebo,啊,看到这是 C++11 imo 的最佳功能之一,真是太糟糕了。 对于未来的访问者,Visual Studio 2012 中添加了 ranged-for。 这如何回答这个问题?您在代码中的哪个位置将函数应用于 std::vector 的每个元素?我只看到迭代。此外,您的第一个示例复制元素,第二个示例通过 const & 传递它们,因此任何修改都在副本上完成或根本无法完成。 @BadDesign,从技术上讲,输出它是应用一个函数,operator<<(std::cout, element)
。我这篇文章的主要目标是向这种语法打开 OP(以及任何未来的访问者)。没有说明不想循环的原因,也可能是不想全部输入。 for_each
中也存在一个循环。第二个例子就是这样 - 一个例子。它表明您可以使用或,这使人们可以随意更改它。此外,谁说你需要修改元素才能在其上调用函数?【参考方案5】:
使用for_each
:
// for_each example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void myfunction (int i)
cout << " " << i;
struct myclass
void operator() (int i) cout << " " << i;
myobject;
int main ()
vector<int> myvector;
myvector.push_back(10);
myvector.push_back(20);
myvector.push_back(30);
cout << "myvector contains:";
for_each (myvector.begin(), myvector.end(), myfunction);
// or:
cout << "\nmyvector contains:";
for_each (myvector.begin(), myvector.end(), myobject);
cout << endl;
return 0;
【讨论】:
【参考方案6】:OP 提到了 Python 中的 map
函数。
这个 Python 函数实际上将一个函数应用于列表(或可迭代)的每个元素,并返回一个收集所有结果的列表(或可迭代)。
换句话说,它做了这样的事情:
def f( x ) :
""" a function that computes something with x"""
# code here
return y
input = [ x1, x2, x3, ... ]
output = map( func, input )
# output is now [ f(x1), f(x2), f(x3), ...]
因此,与 Python 映射最接近的 C++ 标准库实际上是 std::transform
(来自 <algorithm>
标头)。
示例用法如下:
#include <vector>
#include <algorithm>
using namespace std;
double f( int x )
// a function that computes the square of x divided by 2.0
return x * x / 2.0 ;
int main( )
vector<int> input 1, 5, 10 , 20;
vector<double> output;
output.resize( input.size() ); // unfortunately this is necessary
std::transform( input.begin(), input.end(), output.begin(), f );
// output now contains f(1), f(5), f(10), f(20)
// = 0.5, 12.5, 50.0, 200.0
return 0;
【讨论】:
【参考方案7】:您可以使用std::for_each,它采用一对迭代器和一个函数或函子。
【讨论】:
【参考方案8】:如果有人更喜欢它们,我想我会分享 for_each
和 transform
的 std::ranges
等价物:
std::vector<int> v;
std::ranges::for_each(v,[](const auto& n) );
const auto squared = v | std::views::transform([](const auto& n) return n*2; );
在 Godbolt 上运行:https://godbolt.org/z/zYME6b
【讨论】:
以上是关于在 C++ 向量的每个元素上调用函数的主要内容,如果未能解决你的问题,请参考以下文章