假设我有一个vector带有各种条目,我想插入另一个向量,同时省略满足条件的条目.
例如,我想插入一个向量,同时省略所有三个.
{1, 3, 2, 3, 4, 5, 3} -> { /* previous content, */ 1, 2, 4, 5}
Run Code Online (Sandbox Code Playgroud)
到目前为止我提出的用途std::partition,它不保留相对顺序并重新排列源向量.
std::vector<int> source({1, 3, 2, 3, 4, 5, 3});
std::vector<int> target;
auto partition = std::partition(std::begin(source),
std::end(source), [](const auto& a) { return a == 3; });
target.insert(std::begin(target), partition, std::end(source));
Run Code Online (Sandbox Code Playgroud)
我正在寻找的更多是一个迭代器,它检查条件并在条件不满足时继续运行.像这样的东西:
target.insert(std::begin(target),
conditional_begin(source, [](const auto& a) { return a != 3; },
conditional_end(source));
Run Code Online (Sandbox Code Playgroud)
我想一个conditional_end函数是必要的,因为std::end它将返回一个不同的迭代器类型conditional_begin.
也许我忽略了一些事情,所以我的问题是:
Nat*_*ica 14
有没有不同的简单方法来实现我的目标?
是的,标准已经内置了这个功能.您正在寻找的功能是std::copy_if.
std::vector<int> source({1, 3, 2, 3, 4, 5, 3});
std::vector<int> target;
std::copy_if(source.begin(),
source.end(),
std::back_inserter(target), [](auto val){ return val != 3; });
Run Code Online (Sandbox Code Playgroud)
在这里,std::back_inserter(target)将呼吁push_back在target该断言返回的每个元素true.
是的,您可以创建一个满足您需要的自定义迭代器,但是使用标准C ++创建自定义迭代器目前有点繁琐。它看起来像这样:
template <typename Itr, typename F>
struct ConditionalIterator {
Itr itr;
Itr end;
F condition;
using value_type = typename Itr::value_type;
using difference_type = typename Itr::difference_type;
using pointer = typename Itr::pointer;
using reference = typename Itr::reference;
using iterator_category = std::forward_iterator_tag;
ConditionalIterator() = default;
ConditionalIterator(Itr itr, Itr end, F condition): itr(itr), end(end), condition(condition) {}
bool operator!=(const ConditionalIterator &other) const { return other.itr != itr; }
reference operator*() const { return *itr; }
pointer operator->() const { return &(*itr); }
ConditionalIterator& operator++() {
for (; ++itr != end;) {
if (condition(*itr))
break;
}
return *this;
}
ConditionalIterator operator++(int) {
ConditionalIterator ret(*this);
operator++();
return ret;
}
};
Run Code Online (Sandbox Code Playgroud)
然后,您可以创建所需的诸如conditional_beginand conditional_end函数之类的东西。唯一的问题是std::vector::insert期望两个迭代器具有相同的类型。如果我们使用lambda作为条件,则这将成为条件迭代器类型的一部分。因此,我们需要将lambda传递给两个辅助函数,以便它们返回具有匹配类型的迭代器:
template <typename C, typename F>
auto conditional_begin(const C &source, F f) {
return ConditionalIterator<typename C::const_iterator, F>(source.begin(),
source.end(), f);
}
template <typename C, typename F>
auto conditional_end(const C &source, F f) {
return ConditionalIterator<typename C::const_iterator, F>(source.end(),
source.end(), f);
}
Run Code Online (Sandbox Code Playgroud)
您可以使用如下lambda进行调用:
auto condition = [](const auto &a) { return a != 3; };
target.insert(std::begin(target),
conditional_begin(source, std::ref(condition)),
conditional_end(source, std::ref(condition)));
Run Code Online (Sandbox Code Playgroud)
现场演示。
我的粗略测试表明,在这种情况下,这比使用简单要快得多,copy_if并且back_inserter因为std::vector::insert在插入之前先计算出要分配多少内存。仅使用back_inserter将导致多个内存分配。性能上的差异将取决于评估条件的成本。count_if在使用之前,您可以通过保留足够的空间来获得相同的加速copy_if:
auto count = static_cast<size_t>(std::count_if(source.begin(),
source.end(), condition));
target.reserve(target.size() + count);
std::copy_if(source.begin(),
source.end(),
std::back_inserter(target), condition);
Run Code Online (Sandbox Code Playgroud)
现场演示。