3

我有两个向量

std::vector<int>   markedToBeRead(7);   // contains: 1,1,0,0,1,0,1
std::vector<float> myVec(7);            // contains: 1,2,3,4,5,6,7

从 myVec 中获取这些元素的最佳方法是什么,其中 的相应索引markedToBeRead具有 value 1
这是否可能不使用 for 循环,但使用 stl 方法?

std::vector<float> myResult;            // contains: 1,2,5,7

谢谢!

4

5 回答 5

4

显然,这里更喜欢简单的 for 循环,而不是任何 STL 算法。

但就像一个概念的证明一样,这里可以采用 stl::equals 和来自 C++11 的 lambda:

std::equal(myVec.begin(), myVec.end(), markedToBeRead.begin(), [&](float item, int mark)->bool {
    if (mark)
        myResult.push_back(item);
    return true;
});

这有效,但看起来很难看。

于 2012-06-19T10:23:34.037 回答
3

这是我为此编写算法的方法:

template <typename I, typename O, typename M>
void mask_copy(I begin, I end, O obegin, M mbegin) {
    for (; begin != end; ++begin, ++mbegin)
        if (*mbegin)
            *obegin++ = *begin;
}

像这样调用:

int a[] = { 1, 2, 3, 4, 5, 6, 7, 8 , 9 };
bool m[] = { true, false, false, false, true, false, false, true, false };

std::vector<int> out;
mask_copy(begin(a), end(a), back_inserter(out), begin(m));

std::begin(对于和需要 C++11 std::end。)

也就是说,库中的正确实现可能会使用enable_if(or static_assert) 来确保所使用的迭代器类型与其用途兼容,即,它I是一个输入迭代器、O一个兼容的输出迭代器和M一个其value_typeis的输入迭代器bool。不幸的是,缺乏概念会导致名副其实的模板“爆炸”。

于 2012-06-19T10:58:44.310 回答
2

像这样的东西?

for (unsigned int i = 0; i < myVec.length(); i++)
    if (markedToBeRead[i] == 1)
        myResult.push_back(myVec[i]);
于 2012-06-19T09:57:06.333 回答
2

在功能方面,这很简单:它是两个输入范围的 zip,然后是标记为 1 的过滤器,然后是映射以仅提取值。

不幸的是,C++ 标准算法不太适合组合。如果您不介意创建中间容器,您可以应用二进制版本的transform,后跟copy_if(或remove_copy_if在 C++03 中,将谓词颠倒,或remove_if修改您的中间容器),然后应用一元版本的transform.

或者,Boost 以迭代器适配器的形式提供前两个操作。像这样的东西(未经测试):

struct marked {
    bool operator()(boost::tuple<int, float> t) {
        return t.get<0>() == 1;
    }
};

auto first = boost::make_zip_iterator(boost::make_tuple(markedToBeRead.begin(), myVec.begin());
auto last = boost::make_zip_iterator(boost::make_tuple(markedToBeRead.end(), myVec.end());

std::transform(
    boost::make_filter_iterator<marked>(first, last),
    boost::make_filter_iterator<marked>(last, last),
    std::back_inserter(myResults);
    [](boost:tuple<int, float> t) { return t.get<1>(); }
);

您现在可能已经确信 (a) 循环更好,并且 (b) 用其他构造替换循环是 C++ 中的一种旁观运动;-)

如果您需要链接进一步的操作,那么std::transform也可以用迭代器适配器替换:transform_iterator.

于 2012-06-19T11:08:42.070 回答
0

这对我有用:

#include <algorithm>
#include <iostream>
#include <vector>

int main()  {
        std::vector<int>   markedToBeRead = {  1,1,0,0,1,0,1 };
        std::vector<float> myVec = { 1, 2, 3, 4, 5, 6, 7};

        // copy
        std::vector<float> result;
        std::copy_if(myVec.begin(), myVec.end(),
                std::back_inserter(result), [&](const float & f) {
                        return markedToBeRead[&f - &myVec[0]] == 1;
                });

        // Check result
        for (std::vector<float>::size_type i = 0; i < result.size(); ++i)
                std::cout << result[i] << " ";
}

在 Ideone 上测试。

于 2012-06-19T11:12:15.357 回答