我遇到问题,我需要根据存储在前一个元素中的信息修改容器的元素。例如:
If previous vector element is divisable by 2 then multiply current element by 10
vec -> [12, 11, 33, 10]
我试图找到很好地包装此操作的算法,但我无法找到它。我带着想法来了,但我不太喜欢这个解决方案。
check if vector's size is bigger than 1
auto last_element_it = vec.end();
--last_element_it;
for (auto it = vec.begin(); it != last_element_it; ++it)
{
auto next_element_it = it;
++next_element_it;
// do whatever I want with it and next_element_it
}
有没有更简单和/或更漂亮的方法呢?
@EDIT 示例中的整数仅用于简化此问题。在我的真正问题中,我在容器中有类对象。
答案 0 :(得分:2)
您可以使用算法std::adjacent_find为每个相邻对执行操作。如果范围为空或仅包含单个元素,则不会发生任何事情。
std::adjacent_find(vec.begin(), vec.end(), [&](const auto& lhs, const auto& rhs) {
// do something with pair of adjacent elements
foobar(lhs, rhs);
return false;
});
操作始终返回false
,因为std::adjacent_find
将停止在操作返回true
的第一对上。
根据C ++标准,不允许在解除引用的迭代器上调用非const函数。但是,您可以编写自己的std::adjacent_find
版本,但没有这些限制:
template <class ForwardIt, typename BinaryPredicate>
void for_each_adjacent(ForwardIt first, ForwardIt last, BinaryPredicate p)
{
if (first == last) {
// nothing
} else {
for (ForwardIt next = std::next(first); next != last; ++next, ++first) {
p(*first, *next);
}
}
}
答案 1 :(得分:1)
std::experimental::optional<int> prev;
for( int& x : container ) {
if (prev && ((*prev % 2)==0)) {
x*=10;
}
prev = x;
}
使用post-C ++ 1y std::experimental::optional
。分支最终具有高度可预测性,因此分支预测失败的情况很少见。
如果你有一堆范围和容器适配器,我会写:
for( auto it : skip_first( as_iterators( container ) ) ) {
auto prev = std::prev(it);
}
其中as_iterators
获取范围并在范围内的迭代器上返回不可变范围,skip_first
获取范围并返回没有第一个元素的范围(如果源范围为空,则返回空)。
这些都不值得写,但我发现在C ++泛型编程中写这种东西是一个很好的练习。请记住,如果您将rvalue作为输入,则存储move
ed-to副本而不是rvalue引用,以便您可以菊花链式连接它们。
答案 2 :(得分:0)
因为你正在处理矢量,老式的方式很好......
#include <iostream>
#include <vector>
#include <iterator>
using vec_t = std::vector<int>;
using namespace std;
void by_10_next_after_even(vec_t& vec) {
for(size_t i = 1 ; i < vec.size() ; ++i) {
if (0 == vec[i-1] % 2) {
vec[i] *= 10;
return; // or break if you prefer
}
}
}
void by_10_all_after_even(vec_t& vec) {
for (size_t i = 1 ; i < vec.size() ; ++i) {
if (0 == (vec[i-1] % 2)) {
for ( ; i < vec.size() ; ++i) {
vec[i] *= 10;
}
return; // or break if you prefer
}
}
}
int main()
{
vec_t test1 = { 9, 7, 3, 6, 7, 2 };
by_10_next_after_even(test1);
vec_t test2 = { 9, 7, 3, 6, 7, 2 };
by_10_all_after_even(test2);
copy(test1.begin(), test1.end(), ostream_iterator<int>(cout, " "));
cout << endl;
copy(test2.begin(), test2.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}