将所有满足某些条件的元素从一个容器移动到另一个容器,即我正在寻找某种"move_if"

Move all elements which satisfy some condition from one container to another, i.e. I'm looking for some kind of "move_if"

本文关键字:另一个 寻找 if move 移动 元素 条件 一个 满足      更新时间:2023-10-16

给定

std::vector<T> first = /* some given data */, second;

我想将满足某些条件cond(e)的所有元素efirst移动到second,即类似的东西

move_if(std::make_move_iterator(first.begin()),
    std::make_move_iterator(first.end()),
    std::back_inserter(second), [&](T const& e)
{
        return cond(e);
});

我无法用算法库建立这一点。那么,我该怎么做呢?

如果移出的元素可以留在first中的位置,那么只需将copy_ifmove_iterator一起使用即可。

std::copy_if(std::make_move_iterator(first.begin()),
             std::make_move_iterator(first.end()),
             std::back_inserter(second), cond);

如果移动的元素应该从first中删除,我会进行

// partition: all elements that should not be moved come before 
// (note that the lambda negates cond) all elements that should be moved.
// stable_partition maintains relative order in each group
auto p = std::stable_partition(first.begin(), first.end(),
                               [&](const auto& x) { return !cond(x); });
// range insert with move
second.insert(second.end(), std::make_move_iterator(p),
                            std::make_move_iterator(first.end()));
// erase the moved-from elements.
first.erase(p, first.end());

或者partition_copymove_iterator,后面跟着赋值:

std::vector<T> new_first;
std::partition_copy(std::make_move_iterator(first.begin()),
                    std::make_move_iterator(first.end()),
                    std::back_inserter(second), std::back_inserter(new_first), cond);
first = std::move(new_first);

move_if不存在的原因是它会膨胀库。可以将copy_if与move迭代器一起使用,也可以自己编写。

copy_if(move_iterator<I>(f), move_iterator<I>(l), out);

以下是Jonas_No在channel9上的一个实现。

template <typename FwdIt, typename Container, typename Predicate>
inline FwdIt move_if(FwdIt first, FwdIt last, Container &cont, Predicate pred)
{
    if (first == last)
        return last; // Empty so nothing to move
    const size_t size = count_if(first, last, pred);
    if (size == 0)
        return last; // Nothing to move
    cont.resize(size);
    FwdIt new_end = first;
    auto c = cont.begin();
    for (auto i = first; i != last; ++i)
    {
        if (pred(*i)) // Should it move it ?
            *c++ = move(*i);
        else
            *new_end++ = move(*i);
    }
    return new_end;
}

@T.C.提供了一个完美的工作解决方案。然而,乍一看,人们可能不理解该代码的意图。因此,它可能并不完美,但我倾向于这样的东西:

template<class InputIt, class OutputIt, class InputContainer, class UnaryPredicate>
OutputIt move_and_erase_if(InputIt first, InputIt last, InputContainer& c, OutputIt d_first, UnaryPredicate pred)
{
    auto dist = std::distance(first, last);
    while (first != last)
    {
        if (pred(*first))
        {
            *d_first++ = std::move(*first);
            first = c.erase(first);
            last = std::next(first, --dist);
        }
        else
        {
            ++first;
            --dist;
        }
    }
    return d_first;
}
相关文章: