修改容器的对/邻居

时间:2014-05-05 18:22:22

标签: c++ c++11

我遇到问题,我需要根据存储在前一个元素中的信息修改容器的元素。例如:

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 示例中的整数仅用于简化此问题。在我的真正问题中,我在容器中有类对象。

3 个答案:

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