给定一个包含要切片索引的向量,是否有一种有效的方法来切片 C++ 向量

luc*_*uca 5 c++ boost vector slice

我正在努力将用 MATLAB 编写的代码实现为 C++。

在 MATLAB 中,您可以将一个数组与另一个数组进行切片,例如 A(B),这会生成一个由 A 中的元素组成的新数组,其索引由 B 中的元素值指定。

我想在 C++ 中使用向量做类似的事情。这些向量的大小为 10000-40000 个 double 类型的元素。

我希望能够使用另一个包含要切片索引的 int 类型向量来对这些向量进行切片。

例如,我有一个向量 v = <1.0, 3.0, 5.0, 2.0, 8.0> 和一个向量 w = <0, 3, 2>。我想使用 w 对 v 进行切片,以便切片的结果是一个新向量(因为旧向量必须保持不变)x = <1.0, 2.0, 5.0>。

我想出了一个函数来做到这一点:

template<typename T>
std::vector<T> slice(std::vector<T>& v, std::vector<int>& id) {

    std::vector<T> tmp;
    tmp.reserve(id.size());

    for (auto& i : id) {
        tmp.emplace_back(v[i]);
    }

    return tmp;
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否有更有效的方法来完成这样的任务。速度是这里的关键,因为该切片函数将位于一个大约有 300000 次迭代的 for 循环中。我听说 boost 库可能包含一些有效的解决方案,但我还没有使用它的经验。

我使用 chrono 库来测量调用此切片函数所需的时间,其中要切片的向量的长度为 37520,包含索引的向量的大小为 1550。对于此函数的单次调用,经过的时间 = 0.0004284s 。然而,超过 300000 次 for 循环迭代,总耗时为 134 秒。

任何建议将不胜感激!

Pau*_*ers 3

emplace_back有一些开销,因为它涉及一些内部会计std::vector。试试这个:

template<typename T>
std::vector<T> slice(const std::vector<T>& v, const std::vector<int>& id) {

    std::vector<T> tmp;
    tmp.resize (id.size ());

    size_t n = 0;
    for (auto i : id) {
        tmp [n++] = v [i];
    }

    return tmp;
}
Run Code Online (Sandbox Code Playgroud)

另外,我删除了内部循环中不必要的取消引用。


编辑:我对此进行了更多思考,并受到@jack的回答的启发,我认为内部循环(这是最重要的)可以进一步优化。这个想法是将循环使用的所有内容都放在局部变量中,这为编译器提供了优化代码的最佳机会。所以试试这个,看看你能得到什么时间。确保您测试了发布/优化版本:

template<typename T>
std::vector<T> slice(const std::vector<T>& v, const std::vector<int>& id) {

    size_t id_size = id.size ();
    std::vector<T> tmp (id_size);
    T *tmp_data = tmp.data ();

    const int *id_data = id.data ();
    const T* v_data = v.data ();

    for (size_t i = 0; i < id_size; ++i) {
        tmp_data [i] = v_data [id_data [i]];
    }

    return tmp;
}
Run Code Online (Sandbox Code Playgroud)

  • `std::vector&lt;T&gt; tmp(id.size());` (3认同)