std::for_each、std::transform、std::for_each_n

lambda表达式

1.for_each:应用函数到范围中的元素

for_each可以理解为一个for循环:依次对范围中的元素进行合法操作。
中文标准库:for_each

  • 函数原型:
template< class InputIt, class UnaryFunction >
  UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );

//C++17起
template< class ExecutionPolicy, class ForwardIt, class UnaryFunction2 >
  void for_each( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryFunction2 f );

//C++20起
template< class InputIt, class UnaryFunction >
  constexpr UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );

2.transform:将函数应用到某一范围各个元素,并在目标范围存储结果

中文标准库:transform

  • 函数原型:
//unary operation
template <class InputIterator, class OutputIterator, class UnaryOperation>
    OutputIterator transform(InputIterator first1, InputIterator last1,OutputIterator result, UnaryOperation op);

//binary operation
template <class InputIterator1, class InputIterator2,class OutputIterator, class BinaryOperation>
    OutputIterator transform(InputIterator1 first1, InputIterator1 last1,InputIterator2 first2, OutputIterator result,BinaryOperation binary_op);

注意:transform输出参数(保存结果的参数)必须有足够的大小,可以使用resize重新分配大小,不能用reserve

3.transform和for_each的区别:

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
	{
		std::vector<int> vec1{ 1,2,3,4,5 };

		auto it = vec1.begin();
		std::advance(it, 3);
		std::for_each(vec1.begin(), it, [](int& i) {i = i * 2; });
		std::for_each(vec1.begin(), vec1.end(), [](int& i) {return i * 2; });  //lambda表达式没有对vec1的元素进行修改,所以vec1没有变化
		std::for_each(vec1.begin(), vec1.end(), [](int i) {return ++i; });     //值捕获,不会改变vec1
		std::for_each(vec1.begin(), vec1.end(), [](int& i) {return ++i; });    //引用捕获,vec1 = {2,3,4}
		std::for_each(vec1.begin(), vec1.end(), [](int& i) {i = -i; });        //vec1 = {-2,-3,-4}
	}

	{
		std::vector<int> vec1{ 1,2,3,4,5 };
		std::vector<int> vec2;
		// 此处lambda的作用就是将vec1的每一个值乘2后赋值给vec2,对vec1并没有做任何修改
		std::for_each(vec1.begin(), vec1.end(), 
			[&vec2](const int i) {
				vec2.emplace_back(i*2);
			});
	}

	{ // 以下代码和上面的lambda效果一模一样
		std::vector<int> vec1{ 1,2,3,4,5 };
		std::vector<int> vec2;
		for (auto elem : vec1)
			vec2.emplace_back(elem);
	}

	{
		std::vector<int> vec1{ 1,2,3,4,5 };
		std::vector<int> vec2;
		vec2.resize(vec1.size());
		std::transform(vec1.begin(), vec1.end(), vec2.begin(), [](int i) {return -i; });  //vec2 = {-1,-2,-3,-4,-5},vec2必须提前分配好大小
		std::transform(vec1.begin(), vec1.end(), vec1.begin(), [](int i) {return -i; });  //vec1 = {-1,-2,-3,-4,-5}
		//std::transform(vec1.begin(), vec1.end(), vec2.begin(), [](int& i) {++i; });   //报错:“ = ”: 无法从“void”转换为“int”,所以此处的函数对象必须有返回值,用来输出到vec2
	}
	return 0;
}
  • for_each参数中的函数对象不需要return一个值,而是将函数对象直接作用到传入的参数上,所以函数对象的lambda表达式一般都是引用捕获

  • transform是通过参数中的函数对象对传入的参数进行处理,然后存放在一个传入的容器中(可以是原操作容器),必须返回一个类型一致的值(用来存储结果)

  • std::transform 不保证按顺序应用 unary_op 或 binary_op 。为按顺序应用函数到数列,或应用修改序列元素的函数,应使用 std::for_each 。

4.for_each_n(C++17):应用一个函数对象到序列的前n个元素

  • 函数原型
template< class InputIt, class Size, class UnaryFunction >
  InputIt for_each_n( InputIt first, Size n, UnaryFunction f );

示例代码:

#include <algorithm>
#include <vector>

int main()
{
	std::vector<int> vec1{ 1,2,3,4,5 };
	std::for_each_n(vec1.begin(), 3, [](auto& n) { n *= 2; });
	//上下两种方法等价
	std::vector<int> vec2{ 1,2,3,4,5 };
	auto it = vec2.begin();
	std::advance(it, 3);
	std::for_each(vec2.begin(), it, [](int& i) {i *= 2; });

	return 0;
}
posted @ 2020-11-25 17:42  滴哒哒哒  阅读(211)  评论(0编辑  收藏  举报