将一元函数应用于向量的某些元素的良好实现是什么?
What's a good implementation of applying a unary function to some elements of a vector?
我想将函数 UnaryFunction f
应用于 std 容器的某些元素,给定谓词 UnaryPredicate p
- 如果将 std::partition
and then apply std::for_each
组合到其中一个分区。
我对 C++ 很陌生,请原谅我的无知。然而,我已经在 <algorithm>
中寻找合适的实现,但我似乎无法找到所需的功能。
基于 cppreference.com 上的可能实现,我得出以下结论:
template<class InputIt, class UnaryPredicate, class UnaryFunction>
UnaryFunction for_each_if(InputIt first, InputIt last, UnaryPredicate p, UnaryFunction f)
{
for (; first != last; ++first) {
if (p(*first))
{
f(*first);
}
}
return f;
}
return 值是根据 std::for_each
建模的,尽管 OutputIter
可能是更好的选择。不过这需要更复杂的实现,所以这次我选择了简洁而不是巧妙。替代实现留作 reader.
的练习
我的问题是:在 std 库中是否已经建立了执行此操作的方法?如果不是,这是否是这样一个函数模板的合理实现?
就评论而言,std 库中似乎没有实现这一点。但是,正如 user2672165 指出的那样,谓词可能很容易包含在函数中。为了说明这一点,请参阅 for_each
example over at cppreference.com 的以下修改版本:
#include <vector>
#include <algorithm>
#include <iostream>
struct Sum {
Sum() { sum = 0; }
void operator()(int n) { sum += n; }
int sum;
};
int main()
{
std::vector<int> nums{3, 4, 2, 9, 15, 267};
std::cout << "before: ";
for (auto n : nums) {
std::cout << n << " ";
}
std::cout << '\n';
std::for_each(nums.begin(), nums.end(), [](int &n){ if (n > 5) n++; });
// Calls Sum::operator() for each number
Sum s = std::for_each(nums.begin(), nums.end(), Sum());
std::cout << "after: ";
for (auto n : nums) {
std::cout << n << " ";
}
std::cout << '\n';
std::cout << "sum: " << s.sum << '\n';
}
在这里,谓词被添加到函数中,因此 [](int &n){ n++; }
现在变成 [](int &n){ if (n > 5) n++; }
仅将函数应用于大于 5 的整数元素。
预期输出为
before: 3 4 2 9 15 267
after: 3 4 2 10 16 268
sum: 303
希望这对其他人有帮助。
STL 不能很好地支持算法的组合。如您所说,如果您不关心元素的顺序,可以先调用 partition
,然后在其中一个分区上调用 for_each
。
对于一个新项目,或者一个你可以引入库的项目,我强烈建议看一下范围库,例如Boost.Range 或 Eric Niebler's range-v3.
有了range库,可以这样做:
template<typename R, typename P, typename F>
F for_each_if(R& rng, P pred, F f)
{
using namespace boost::adaptors;
return (rng | filtered(pred) | for_each(f));
}
我想将函数 UnaryFunction f
应用于 std 容器的某些元素,给定谓词 UnaryPredicate p
- 如果将 std::partition
and then apply std::for_each
组合到其中一个分区。
我对 C++ 很陌生,请原谅我的无知。然而,我已经在 <algorithm>
中寻找合适的实现,但我似乎无法找到所需的功能。
基于 cppreference.com 上的可能实现,我得出以下结论:
template<class InputIt, class UnaryPredicate, class UnaryFunction>
UnaryFunction for_each_if(InputIt first, InputIt last, UnaryPredicate p, UnaryFunction f)
{
for (; first != last; ++first) {
if (p(*first))
{
f(*first);
}
}
return f;
}
return 值是根据 std::for_each
建模的,尽管 OutputIter
可能是更好的选择。不过这需要更复杂的实现,所以这次我选择了简洁而不是巧妙。替代实现留作 reader.
我的问题是:在 std 库中是否已经建立了执行此操作的方法?如果不是,这是否是这样一个函数模板的合理实现?
就评论而言,std 库中似乎没有实现这一点。但是,正如 user2672165 指出的那样,谓词可能很容易包含在函数中。为了说明这一点,请参阅 for_each
example over at cppreference.com 的以下修改版本:
#include <vector>
#include <algorithm>
#include <iostream>
struct Sum {
Sum() { sum = 0; }
void operator()(int n) { sum += n; }
int sum;
};
int main()
{
std::vector<int> nums{3, 4, 2, 9, 15, 267};
std::cout << "before: ";
for (auto n : nums) {
std::cout << n << " ";
}
std::cout << '\n';
std::for_each(nums.begin(), nums.end(), [](int &n){ if (n > 5) n++; });
// Calls Sum::operator() for each number
Sum s = std::for_each(nums.begin(), nums.end(), Sum());
std::cout << "after: ";
for (auto n : nums) {
std::cout << n << " ";
}
std::cout << '\n';
std::cout << "sum: " << s.sum << '\n';
}
在这里,谓词被添加到函数中,因此 [](int &n){ n++; }
现在变成 [](int &n){ if (n > 5) n++; }
仅将函数应用于大于 5 的整数元素。
预期输出为
before: 3 4 2 9 15 267
after: 3 4 2 10 16 268
sum: 303
希望这对其他人有帮助。
STL 不能很好地支持算法的组合。如您所说,如果您不关心元素的顺序,可以先调用 partition
,然后在其中一个分区上调用 for_each
。
对于一个新项目,或者一个你可以引入库的项目,我强烈建议看一下范围库,例如Boost.Range 或 Eric Niebler's range-v3.
有了range库,可以这样做:
template<typename R, typename P, typename F>
F for_each_if(R& rng, P pred, F f)
{
using namespace boost::adaptors;
return (rng | filtered(pred) | for_each(f));
}