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

cbeh67ev  于 11个月前  发布在  其他
关注(0)|答案(3)|浏览(118)

我正在努力实现一个代码,这是写在MATLAB到C++。
在MATLAB中,你可以用另一个数组来切片一个数组,比如A(B),这会导致A的元素在B中的元素值指定的索引处的一个新数组。
我想在C++中使用vector做类似的事情。这些vector的大小为10000-40000个double类型的元素。
我希望能够使用另一个int类型的vector来切片这些vector,其中包含要切片的索引。
例如,我有一个向量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;
}

字符串
我想知道是否有可能更有效的方法来完成这样的任务。速度是这里的关键,因为这个切片函数将在一个大约300000次迭代的for循环中。我听说boost库可能包含一些有效的解决方案,但我还没有使用它的经验。
我使用了chrono库来测量调用这个slice函数所花费的时间,其中要切片的vector的长度为37520,包含索引的vector的大小为1550。对于这个函数的单次调用,所花费的时间= 0.0004284 s。然而,超过300000次for循环迭代,总花费的时间是134 s。
任何建议将非常感谢!

ds97pgxw

ds97pgxw1#

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

字符串
此外,我删除了你的内部循环中不必要的解引用。

**编辑:**我又想了想,受到@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;
}

xxslljrj

xxslljrj2#

性能似乎有点慢;你是用编译器优化构建的(例如g++ main.cpp -O3,或者如果使用IDE,切换到发布模式)。仅这一点就将计算时间加快了10倍左右。
如果你已经在使用优化了,通过使用基本的for循环迭代,(for int i = 0; i < id.size(); i++)的计算时间在我的机器上加快了2- 3倍,这个想法是,编译器不必解析auto引用的类型,而且由于基本的for循环一直在C++中,编译器可能有很多技巧来加速它。

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

    // @Jan Schultke's suggestion
    std::vector<T> tmp(id.size ());

    size_t n = 0;
    for (int i = 0; i < id.size(); i++) {
        tmp [n++] = v [i];
    }

    return tmp;
}

字符串

bksxznpy

bksxznpy3#

我想在C中使用vector做类似的事情。
C
对Matlab的可切片向量的回答不是std::vector;而是std::valarray
https://en.cppreference.com/w/cpp/numeric/valarray
Cstd::valarray支持在std::slice的帮助下示例化其他std::valarray对象。
一旦你有了valarray slice对象,C
std::valarray显式地支持对它的每个元素应用标量操作,不仅是基本的算术操作,而且还通过将函数传递给std::valarray::apply来对它的每个元素应用函数。

相关问题